如何拦截 DbContext 中的 ModelBuilder 实例?
How can I intercept the ModelBuilder instance in a DbContext?
我正在编写一个库,它将围绕 Entity Framework Core 5+ 中的 DbContext
class 提供新的 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 class:我可以继承
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
实现的方式拦截它,那对我有帮助。
欢迎提出任何想法。
谢谢。
负责调用 OnModelCreating
的 EF Core 服务被调用 IModelCustomizer
使用单一方法
public void Customize(ModelBuilder modelBuilder, DbContext context);
拦截那个方法可以让你做你想做的事。唯一的问题是 EF Core 没有提供一种简单的方法来 覆盖 现有的实现。唯一可用的方法是 ReplaceService
,它是全有或全无,其明显缺点是如果您只想执行基本实现的 pre/post 处理,您需要知道哪个是 class你正在更换。当然,其他一些扩展也可以替换您的实现(最后获胜)。
正确实施需要一堆用于注册自定义 IDbContextOptionsExtension
to be able to manipulate directly services collection inside ApplyServices
方法的样板。如果您有兴趣,可以在其他 EF Core 扩展库(例如 LinqKit)中找到示例。
假设没有其他扩展覆盖有问题的服务,并且知道默认的 EF Core 实现目前由 ModelCustomizer
class in general or RelationalModelCustomizer
class 为关系数据库提供(但目前没有添加任何东西到简单调用 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)...
}
}
}
我正在编写一个库,它将围绕 Entity Framework Core 5+ 中的 DbContext
class 提供新的 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 class:我可以继承
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
实现的方式拦截它,那对我有帮助。
欢迎提出任何想法。
谢谢。
负责调用 OnModelCreating
的 EF Core 服务被调用 IModelCustomizer
使用单一方法
public void Customize(ModelBuilder modelBuilder, DbContext context);
拦截那个方法可以让你做你想做的事。唯一的问题是 EF Core 没有提供一种简单的方法来 覆盖 现有的实现。唯一可用的方法是 ReplaceService
,它是全有或全无,其明显缺点是如果您只想执行基本实现的 pre/post 处理,您需要知道哪个是 class你正在更换。当然,其他一些扩展也可以替换您的实现(最后获胜)。
正确实施需要一堆用于注册自定义 IDbContextOptionsExtension
to be able to manipulate directly services collection inside ApplyServices
方法的样板。如果您有兴趣,可以在其他 EF Core 扩展库(例如 LinqKit)中找到示例。
假设没有其他扩展覆盖有问题的服务,并且知道默认的 EF Core 实现目前由 ModelCustomizer
class in general or RelationalModelCustomizer
class 为关系数据库提供(但目前没有添加任何东西到简单调用 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)...
}
}
}