我在ASP.Net core
中Entity framework 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.csConfigureServices
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"
}
}
问题:
问题是当我通过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.
请帮助解决这个问题提前谢谢你。
如错误信息所示:
提供程序可以通过覆盖DbContext。方法或使用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>();
});
}
然后将.csproj文件中的Sdk="Microsoft.NET.Sdk"
修改为Sdk="Microsoft.NET.Sdk.Web"
,如下所示:
<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中有Configure方法):
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
命令。