7.3EF Core与ASP.NET Core集成

7.3EF Core与ASP.NET Core集成

案例:

  1. Nuget安装Microsoft.EntityFrameworkCore.Relational、Microsoft.EntityFrameworkCore.Sqlite、Microsoft.EntityFrameworkCore.Tools
  2. 定义Book实体类
public record Book
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
}
  1. 定义Book配置类
public class BookConfig : IEntityTypeConfiguration<Book>
{
    public void Configure(EntityTypeBuilder<Book> builder)
    {
        builder.ToTable("Books");
    }
}
  1. 增加上下文类
public class MyDbContext:DbContext
{
    public DbSet<Book> Books { get; set; }
	//与之前编写的上下文类不同,之前上下文类会重写OnConfiguring方法,并在里面设置连接字符串
    //但现在要求连接字符串要放在配置中
    //后面会在Program.cs中用依赖注入的方式使用MyDbContext,所以在这里加了一个构造函数
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        //设置需要加载的程序集
        //加载当前程序集中所有实现了IEntityTypeConfiguration接口的类
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}
  1. 在appsettings.json中增加数据库连接字符的设置
"ConnectionStrings": { "Default": "Data Source=MySqLite.db" }
  1. 在Program.cs中使用依赖注入的方式对上下文的连接字符进行配置
builder.Services.AddDbContext<MyDbContext>(opt => {
    string constr = builder.Configuration.GetConnectionString("Default");
    opt.UseSqlite(constr);
});
//如果有多个数据库需要配置,可以直接在后面加,因为AddDbContext是泛型的
  1. 增加控制类
[Route("[controller]/[action]")]
public class TestController : ControllerBase
{
    private readonly MyDbContext dbCtx;
    public TestController(MyDbContext dbCtx)
    {
        this.dbCtx = dbCtx;
    }
    [HttpPost]
    public async Task<IActionResult> Index()
    {
        dbCtx.Add(new Book { Id = Guid.NewGuid(), Name = "ddd", Price = 40 });
        await dbCtx.SaveChangesAsync();
        var book = dbCtx.Books.First();
        return Content(book.ToString());
    }
}
  1. 如果在多项目环境下执行Add-Migration迁移命令的时候,迁移工具发生报错。此时可以使用IDesignTimeDbContextFactory接口来解决。当项目中存在一个该接口的时候,迁移工具会调用实现接口类的CreateDbContext方法来获取上下文对象,然后迁移工具使用这个上下文来连接数据库。
//该代码只有在开发环境下才会运行
class MyDesignTimeDbContextFactory:IDesignTimeDbContextFactory<MyDbContext>
{
	public MyDbContext CreateDbContext(string[] args)
	{
		DbContextOptionsBuilder<MyDbContext> builder = new();
        //定义了环境变量,其实可以直接使用字符串
		string connStr = Environment.GetEnvironmentVariable("ConnectionStrings:BooksEFCore");
		builder.UseSqlServer(connStr);
		return new MyDbContext(builder.Options);
	}
}
  1. 使用Add-Migration Init、Update-database等命令完成数据库的创建

上下文池

上下文被创建的时候,要执行实体类的配置,所以会消耗较多的资源,所以EF Core提供了AddDbContextPool来注入上下文,对于使用了AddDbContextPool注入的上下文,EF Core会优先从上下文池中获取实例。但是,因为池中的上下文实例会被反复使用,因此没有办法为上下文注入服务。

在项目开发时,建议使用“小上下文”策略,不要把项目中所有的实体放到一个上下文中,而是要将关联性大的实体放到一个上下文中。

如果采用“小上下文”策略,则需要手动注册所有的上下文,批量注册上下文的方法:

public static IServiceCollection AddAllDbContexts(this IServiceCollection services, Action<DbContextOptionsBuilder> builder, IEnumerable<Assembly> assemblies)
{
    Type[] types = new Type[] { typeof(IServiceCollection), typeof(Action<DbContextOptionsBuilder>), typeof(ServiceLifetime), typeof(ServiceLifetime) };
    //通过反射获取AddDbContext方法,1代表只有1个泛型参数
    var methodAddDbContext = typeof(EntityFrameworkServiceCollectionExtensions).GetMethod("AddDbContext",1,types);
    foreach (var asmToLoad in assemblies)
    {
        //获取非抽象的上下文类
        foreach (var dbCtxType in asmToLoad.GetTypes().Where(t=>!t.IsAbstract && typeof(DbContext).IsAssignableFrom(t)))
        {
            //由于AddDbContext是泛型方法,所以先设定泛型
            var methodGenericAddDbContext = methodAddDbContext.MakeGenericMethod(dbCtxType);
            methodGenericAddDbContext.Invoke(null, new object[] { services, builder, ServiceLifetime.Scoped, ServiceLifetime.Scoped });
        }
    }
    return services;
}

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...