InvalidOperationException: Не е конфигуриран доставчик на база данни за този DbContext с модел на хранилище

Моля, имам проблем с Entity framework core в ASP.Net core. Първо, аз съм аматьор както в EF Core, така и в ASP.Net Core.

Идея:

Опитвам се да създам генерично хранилище, за да правя някои повтарящи се процедури, без да повтарям кода, когато работя с множество контексти.

Класът Repo:

public sealed class Repo<TContext> : IRepo<TContext>, IDisposable where TContext : DbContext, new()
{

    


    #region properties

    /// <summary>
    /// Private DBContext property
    /// </summary>
    private DbContext _Context { get; } = null;


    /// <summary>
    /// Determine if Lazy Loading either activate or not
    /// </summary>
    private bool _LazyLoaded { get; set; }

    #endregion




    #region Construcors


    public Repo(bool LazyLoaded)
    {
        _Context                                  = new TContext();
        _LazyLoaded                               = LazyLoaded;
        _Context.ChangeTracker.LazyLoadingEnabled = LazyLoaded;
    }


    #endregion



    
    #region Routines

    


    #region Select

        /// <summary>
        /// Get All records from a table
        /// </summary>
        /// <typeparam name="TEntity">The entity to select from</typeparam>
        /// <returns></returns>
        public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class
        {
            return _Context.Set<TEntity>().ToList();
        }



        /// <summary>
        /// Asynchronously, Get All records from a table
        /// </summary>
        /// <typeparam name="TEntity">The entity to select from</typeparam>
        /// <returns></returns>
        public Task<IEnumerable<TEntity>> GetAllAsync<TEntity>() where TEntity : class
        {
            return Task.Factory.StartNew(() => GetAll<TEntity>());
        }




        /// <summary>
        /// Get One record from a table, based on the primary key value
        /// </summary>
        /// <typeparam name="TEntity">The entity to select from</typeparam>
        /// <param name="pkValue">The primary key value</param>
        /// <returns></returns>
        public TEntity GetOne<TEntity>(object pkValue) where TEntity : class
        {
            return _Context.Set<TEntity>().Find(pkValue);
        }



        /// <summary>
        /// Asynchronously, Get One record from a table, based on the primary key value
        /// </summary>
        /// <typeparam name="TEntity">The entity to select from</typeparam>
        /// <param name="pkValue">The primary key value</param>
        /// <returns></returns>
        public Task<TEntity> GetOneAsync<TEntity>(object pkValue) where TEntity : class
        {
            return Task.Factory.StartNew(() => GetOne<TEntity>(pkValue));
        }






        #region Preview feature


         /// <summary>
        /// Get Many records from a table based on a property value
        /// </summary>
        /// <typeparam name="TEntity">The entity to select from</typeparam>
        /// <param name="prop">The property used in the condition</param>
        /// <param name="val">The value that will used in the search</param>
        /// <returns></returns>
        public IEnumerable<TEntity> GetMany<TEntity>(string prop, object val) where TEntity : class
        {
            return _Context.Set<TEntity>().AsEnumerable()
                           .Where(x => typeof(TEntity).GetProperty(prop).GetValue(x, null).ToString()
                                                      .Contains(val.ToString())).ToList();
        }

    #endregion




    #endregion



    #region Contains

    /// <summary>
    /// Check if a entity contains an object
    /// </summary>
    /// <typeparam name="TEntity">Entity to be look in</typeparam>
    /// <param name="obj">The object to be looking for</param>
    /// <returns></returns>
    public bool Contains<TEntity>(TEntity obj) where TEntity : class
    {
        return _Context.Set<TEntity>().AsEnumerable().Contains(obj);
    }


    /// <summary>
    /// Asynchronously Check if a entity contains an object
    /// </summary>
    /// <typeparam name="TEntity">Entity to be look in</typeparam>
    /// <param name="obj">The object to be looking for</param>
    /// <returns></returns>
    public Task<bool> ContainsAsync<TEntity>(TEntity obj) where TEntity : class
    {
        return Task.Factory.StartNew(() => Contains<TEntity>(obj));
    }




    /// <summary>
    ///  Check if a entity contains an object based on a custom EQUALITY Comparer
    /// </summary>
    /// <typeparam name="TEntity">Entity to be look in</typeparam>
    /// <typeparam name="TEntityComparer">The custom TEntity EQUALITY Comparer</typeparam>
    /// <param name="obj">The object to be looking for</param>
    /// <returns></returns>
    public bool Contains<TEntity, TEntityComparer>(TEntity obj)
        where TEntity : class
        where TEntityComparer : IEqualityComparer<TEntity>, new()
    {
        return _Context.Set<TEntity>().AsEnumerable().Contains(obj,new TEntityComparer() as IEqualityComparer<TEntity>);
    }



    /// <summary>
    ///  Asynchronously Check if a entity contains an object based on a custom EQUALITY Comparer
    /// </summary>
    /// <typeparam name="TEntity">Entity to be look in</typeparam>
    /// <typeparam name="TEntityComparer">The custom TEntity EQUALITY Comparer</typeparam>
    /// <param name="obj">The object to be looking for</param>
    /// <returns></returns>
    public Task<bool> ContainsAsync<TEntity, TEntityComparer>(TEntity obj)
        where TEntity : class
        where TEntityComparer : IEqualityComparer<TEntity>, new()
    {
        return Task.Factory.StartNew(() => Contains<TEntity, TEntityComparer>(obj));
    }

    #endregion



    #region Insert



    /// <summary>
    /// Insert one record into the database table
    /// </summary>
    /// <typeparam name="TEntity">Entity to add into</typeparam>
    /// <param name="record">The record to be added</param>
    public void Insert<TEntity>(TEntity record) where TEntity : class
        {
            _Context.Set<TEntity>().Add(record);
        }



        /// <summary>
        /// Asynchronously, Insert one record into the database table
        /// </summary>
        /// <typeparam name="TEntity">Entity to add into</typeparam>
        /// <param name="record">The record to be added</param>
        public Task InsertAsync<TEntity>(TEntity record) where TEntity : class
        {
            return Task.Factory.StartNew(() => Insert(record));
        }



        /// <summary>
        /// Insert a range of reords in a table
        /// </summary>
        /// <typeparam name="TEntity">Entity to insert into</typeparam>
        /// <param name="records">Records to be inserted</param>
        public void InsertRange<TEntity>(List<TEntity> records) where TEntity : class
        {
            _Context.Set<TEntity>().AddRange(records);
        }



        /// <summary>
        /// Asynchronously, Insert a range of reords in a table
        /// </summary>
        /// <typeparam name="TEntity">Entity to insert into</typeparam>
        /// <param name="records">Records to be inserted</param>
        public Task InsertRangeAsync<TEntity>(List<TEntity> records) where TEntity : class
        {
            return Task.Factory.StartNew(() => InsertRange(records));
        }



        #endregion




    #region Delete

        /// <summary>
        /// Delete One record from a database table
        /// </summary>
        /// <typeparam name="TEntity">Entity to remove from</typeparam>
        /// <param name="record">The record to be removed</param>
        public void Delete<TEntity>(TEntity record) where TEntity : class
        {
            this._Context.Set<TEntity>().Remove(record);
        }



        /// <summary>
        /// Asynchronously, Delete One record from a database table
        /// </summary>
        /// <typeparam name="TEntity">Entity to remove from</typeparam>
        /// <param name="record">The record to be removed</param>
        public Task DeleteAsync<TEntity>(TEntity record) where TEntity : class
        {
            return Task.Factory.StartNew(() => Delete(record));
        }


        #endregion




        /// <summary>
        /// Save the repository changes
        /// </summary>
        public void Save()
        {
            _Context.SaveChanges();
        }


    #endregion




    #region Disposing


        #region Properties

        private bool _disposed { get; set; } = false;

        #endregion


        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _Context.Dispose();
                }
            }

            _disposed = true;
        }



        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }


    #endregion


}

В ядрото на ASP.Net:

Models

  public class Client
    {
        [Key]
        public string ID { get;                         set; }
        public         string             Name   { get; set; }
        public         int                Age    { get; set; }
        public virtual ICollection<Order> Orders { get; set; }
    }


public class Order
{
    [Key]
    public int ID { get;        set; }
    public Client  CLT   { get; set; }
    public string  PRD   { get; set; }
    public decimal Total { get; set; }
}

Кодирайте първия DbContext:

 public class TrainContext:DbContext
    {
        public TrainContext(DbContextOptions<TrainContext> contextOptions) : base(contextOptions)
        {

        }

        public TrainContext()
        {
            
        }

        protected void OnModelCreating(ModelBuilder builder)
        {
            foreach (var property in builder.Model.GetEntityTypes().SelectMany(t => t.GetProperties()).Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
            {
                property.SetColumnType("decimal(18,2)");
            }
        }

        #region DB Sets

        public virtual DbSet<Client> Client { get; set; }
        public virtual  DbSet<Order>  Order  { get; set; }

        #endregion
    }

Client Контролер:

 public class ClientController : Controller
    {
        private readonly Repo<TrainContext> db = new Repo<TrainContext>(false);

        private readonly TrainContext _context;

        public ClientController(TrainContext context)
        {
            _context = context;
        }
        public IActionResult Index()
        {



            //var data = _context.GetAll<Models.Client>();
            var data = _context.Client.ToList();

            ViewBag.Clients = data;

            return View();
        }
    }

Метод Startup.cs ConfigureServices:

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddDbContext<TrainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DB")));

        }

AppSettings.Json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DB": "Server=ServerName; Database=GOrders;Integrated Security=True"
  }
}

Проблемът:

Проблемът е, че това хранилище работи добре, когато предам Db First Context в Конзолно приложение.

Но когато се опитам да използвам това хранилище в моето Asp.Net core приложение с Code first подход, получих тази грешка:

InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.

Моля за помощ за отстраняването на този проблем? и огромни благодарности предварително.


person XDev    schedule 07.02.2021    source източник
comment
вашият DbContext не е конфигуриран с конкретен доставчик на db. Можете да го конфигурирате, като замените метода OnConfiguring или използвате AddDbContext в ConfigureServices метод в Startup клас. Съобщението за изключение ясно обяснява как можете да разрешите проблема. Почти съм сигурен, че когато търсите в Google за тази грешка, трябва да сте успели да намерите решението сами.   -  person King King    schedule 07.02.2021
comment
Моля, можете ли да ми предоставите решение като отговор след вашето разрешение и огромни благодарности за отделеното време, сър   -  person XDev    schedule 07.02.2021
comment
Здравей @XDev, Отговорът ми помогна ли ти да разрешиш проблема си? Ако е така, можеш ли да го приемеш като отговор? Ако не, можеш ли да продължиш, за да ме уведомиш? Вижте: Как да приема като отговор.Благодаря.   -  person Rena    schedule 10.02.2021


Отговори (1)


Както каза съобщението за грешка:

Доставчикът може да бъде конфигуриран чрез замяна на метода „DbContext.OnConfiguring“ или чрез използване на „AddDbContext“ на доставчика на услугата за приложение.

Два начина, по които можете да изпълните вашите изисквания.

Първи начин, заменете DbContext.OnConfiguring:

public class TrainContext : DbContext
{
    public TrainContext(DbContextOptions<TrainContext> contextOptions) : base(contextOptions)
    {

    }

    public TrainContext()
    {

    }

    protected void OnModelCreating(ModelBuilder builder)
    {

        foreach (var property in builder.Model.GetEntityTypes().SelectMany(t => t.GetProperties()).Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
        {
            property.SetColumnType("decimal(18,2)");
        }
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb; Database=GOrders;Integrated Security=true");
    }

    #region DB Sets

    public virtual DbSet<Client> Client { get; set; }
    public virtual DbSet<Order> Order { get; set; }

    #endregion
}

Втори начин с помощта на AddDbContext, но преди да използвате AddDbContext, трябва да добавите някои липсващи неща:

Променете Program.cs:

using Microsoft.AspNetCore.Hosting;  //be sure add these references
using Microsoft.Extensions.Hosting;

class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
      .ConfigureWebHostDefaults(webBuilder =>
      {
          webBuilder.UseStartup<Startup>();
      });
}

След това променете Sdk="Microsoft.NET.Sdk" до Sdk="Microsoft.NET.Sdk.Web" във вашия .csproj файл, както следва:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

</Project>

Подробна причина можете да проверите следната справка:

https://stackoverflow.com/a/58097655/11398810

Startup.cs (Уверете се, че имате метод за конфигуриране в Startup.cs):

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<TrainContext>(options => 
        options.UseSqlServer(Configuration.GetConnectionString("DB")));

    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

След като промените както по-горе, можете да изпълните командата add-migraiton init и update-database.

person Rena    schedule 08.02.2021