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; }
}

Code First 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 не настроен с конкретным поставщиком БД. Вы можете настроить его, переопределив метод 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 (убедитесь, что у вас есть метод Configure в 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