我如何在DbContext中拦截ModelBuilder实例?



我正在写一个库,它将围绕实体框架核心5+中的DbContext类提供新的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).
}
}

在扩展搜索之后,我没有在EF Core API中找到一个扩展点,允许我以非侵入性的方式做到这一点。

这是我目前发现的:

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

理想情况下,我想通过注册DbContext依赖时提供的DbContextOptionsBuilder对象来做到这一点,例如:

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

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

欢迎大家多多指教。

谢谢。

EF负责调用OnModelCreating的核心服务通过单一方法调用IModelCustomizer

public void Customize(ModelBuilder modelBuilder, DbContext context);

拦截该方法允许你做你需要做的事情。唯一的问题是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)...
}
}
}

最新更新