如何拦截 DbContext 中的 ModelBuilder 实例?

yv9*_*89c 3 c# entity-framework entity-framework-core .net-core

我正在编写一个库,它将围绕DbContextEntity Framework Core 5+ 中的类提供新的 API。我已经有了这些新 API 的一个版本,但它需要在最终DbContext实现中进行手动干预,例如:

// Code in the library.
public static class AwesomeExtensions
{
    public static ModelBuilder AddAwesomeExtensionsSupportingEntities(this ModelBuilder modelBuilder)
    {
        // Set up custom entities I need to make this work.
        return modelBuilder;
    }
}

// Code somewhere else.
public class MyBusinessDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // I would like to avoid doing this here.
        modelBuilder.AddAwesomeExtensionsSupportingEntities();

        // Business as usual (database entities).
    }
}
Run Code Online (Sandbox Code Playgroud)

经过长时间的搜索,我没有在 EF Core API 中找到允许我以非侵入式方式执行此操作的扩展点。

这是我到目前为止发现的:

  • CustomDbContext 类:我可以继承DbContext并重写该OnModelCreating方法,但这并不优于我现在正在做的事情。
  • DbContextOptionsBuilder.UseModel:我认为这可能是我可以使用的东西,但增加了太多的复杂性。通过使用此 API,OnModelCreating框架将不会调用该方法。
  • IEntityTypeConfiguration<TEntity>:我支持这个,但它还要求您有权访问该ModelBuilder实例,然后您才能使用该ModelBuilder.ApplyConfigurationsFromAssembly方法。

理想情况下,我想通过DbContextOptionsBuilder注册DbContext依赖项时提供的对象来执行此操作,例如:

// Code in some application.
public void AddServices(IServiceCollection services)
{
    services.AddDbContext<MyBusinessDbContext>(options =>
    {
        // The ideal solution.
        options.UseAwesomeExtensions();
    });
}
Run Code Online (Sandbox Code Playgroud)

如果我只能在ModelBuilder将 的实例提供给OnModelCreating方法之前以不需要修改DbContext实现的方式拦截该实例,那将对我有所帮助。

欢迎任何想法。

谢谢。

Iva*_*oev 6

负责调用的 EF Core 服务使用单一方法OnModelCreating调用IModelCustomizer

public void Customize(ModelBuilder modelBuilder, DbContext context);
Run Code Online (Sandbox Code Playgroud)

拦截该方法可以让您执行您需要的操作。唯一的问题是 EF Core 没有提供覆盖现有实现的简单方法。唯一可用的方法是ReplaceService全有或全无,其明显的缺点是,如果您只想执行基本实现的前/后处理,则需要知道要替换的类是哪个。当然,其他一些扩展也可以取代您的实现(最后的胜利)。

正确实现这一点需要一堆样板来注册自定义,IDbContextOptionsExtension以便能够直接操作内部的服务集合ApplyServices方法内的服务集合。如果您有兴趣,可以在其他 EF Core 扩展库(例如 LinqKit)中找到示例。

假设没有其他扩展覆盖有问题的服务,并且知道当前的默认 EF Core 实现是由ModelCustomizer一般类或RelationalModelCustomizer关系数据库类提供的(但目前没有向简单调用的基本实现添加任何内容OnModelCreating),简化的实现就是继承其中之一并用您的实现替换服务。例如类似的东西

namespace Microsoft.EntityFrameworkCore
{
    using Infrastructure;

    public static class AwesomeDbContextOptionsExtensions
    {
        public static DbContextOptionsBuilder UseAwesomeExtensions(
            this DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder.ReplaceService<IModelCustomizer, AwesomeModelCustomizer>();
    }
}

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
    public class AwesomeModelCustomizer : RelationalModelCustomizer
    {
        public AwesomeModelCustomizer(ModelCustomizerDependencies dependencies)
            : base(dependencies) { }
        public override void Customize(ModelBuilder modelBuilder, DbContext context)
        {
            // Do something before context.OnModelCreating(modelBuilder)...
            base.Customize(modelBuilder, context);
            // Do something after context.OnModelCreating(modelBuilder)...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)