简体   繁体   中英

InvalidOperationException: No database provider has been configured for this DbContext with Repository pattern

Please I have a problem with Entity framework core in ASP.Net core . First of Iam an amateur in both EF Core and ASP.Net Core .

Idea:

Iam trying to create a generic repository to do some repeated routins without repeat the code with when I work with multiple contexts .

The Repo class:

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


}

In ASP.Net core:

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 Controller:

 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 method:

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

The problem:

The problem is this repository is work fine when I pass a Db First Context in a Console application .

But when I try to use this repository in my Asp.Net core application with Code first approach I got this error:

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.

Please any help to fix this issue? and massive thanks in advance.

As the error message said:

A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider.

Two ways you could meet your requirement.

First way ,override the 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
}

Second way by using AddDbContext ,but before using AddDbContext ,you need add some missing things:

Modify 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>();
      });
}

Then modify Sdk="Microsoft.NET.Sdk" to Sdk="Microsoft.NET.Sdk.Web" in your.csproj file as follows:

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

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

</Project>

Detailed reason you could check the following reference:

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

Startup.cs(Be sure you have Configure method in 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?}");
        });
    }
}

After modify like above,then you could run add-migraiton init and update-database command.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM