禁用 EF Core 包含所有属性的约定

问题描述 投票:0回答:2

EF Core(就像之前的 EF)会自动将带有 get/set 的 属性添加到模型中。

我使用 Fluent API,我需要记住忽略它们,这会变得乏味 - 我总是会遇到运行时错误,因为我总是忘记。

我希望 EF 仅包含我已配置的那些属性。

如何禁用此约定?

c# entity-framework entity-framework-core
2个回答
6
投票
在 ConventionSet 对象中调用 DbContext.OnModelCreating 之前,EF Core 会收集将要应用的约定,并且传递给 OnModelCreating 的 ModelBuilber 已包含约定发现的实体和属性。

但是,约定不仅仅代表“一开始就做一次,然后就忘记它们”的规则来确定模型,每当您使用 Fluent API 更改模型时,它们都会不断应用。如果您手动添加实体,则此时将执行发现属性等的约定,并且模型始终保持最新。

ConventionSet 对象定义了“事件”列表,例如“添加的实体类型”,以及每个事件要执行的约定。

其中一个事件是“ModelInitialized”,它在开始时运行,通过 DbSetFindingConvention 初步识别实体。然而,此约定找到的每个实体类型都会触发“事件”EntyTypeAddedConventions,然后该事件将识别实体上的属性等。如果您只是抑制 DbSetFindingConvention,则在手动将实体类型添加到模型后,您仍然会自动获取属性。

为了抑制属性生成,您还需要从 EntyTypeAddedConventions 中删除 PropertyDiscoveryConvention。

删除所有约定可能不是一个好主意,因为您需要手动完成所有操作,这是一项乏味的工作。但是,如果您很好地了解您想要使用哪些自动功能以及哪个约定的作用,您可以有选择地删除其中一些。

要抑制约定,您可以交换 - 特定于数据库提供商! – ConventionSetBuilder 服务实现。

public class CustomSqlServerConventionSetBuilder : SqlServerConventionSetBuilder { //See also notes in CustomRuntimeConventionSetBuilder public CustomSqlServerConventionSetBuilder([NotNullAttribute] ProviderConventionSetBuilderDependencies dependencies, [NotNullAttribute] RelationalConventionSetBuilderDependencies relationalDependencies, [NotNullAttribute] ISqlGenerationHelper sqlGenerationHelper) : base(dependencies, relationalDependencies, sqlGenerationHelper) { } public override ConventionSet CreateConventionSet() { ConventionSet cs = base.CreateConventionSet(); //Do not find entity types automatically DbSetFindingConvention dbSetFindingConvention = cs.ModelInitializedConventions.OfType<DbSetFindingConvention>().FirstOrDefault(); if (dbSetFindingConvention != null) { cs.ModelInitializedConventions.Remove(dbSetFindingConvention); } //Do not find properties automatically PropertyDiscoveryConvention propertyDiscoveryConvention = cs.EntityTypeAddedConventions.OfType<PropertyDiscoveryConvention>().FirstOrDefault(); if (propertyDiscoveryConvention != null) { cs.EntityTypeAddedConventions.Remove(propertyDiscoveryConvention); } propertyDiscoveryConvention = cs.EntityTypeBaseTypeChangedConventions.OfType<PropertyDiscoveryConvention>().FirstOrDefault(); if (propertyDiscoveryConvention != null) { cs.EntityTypeBaseTypeChangedConventions.Remove(propertyDiscoveryConvention); } return cs; } }
替换 DbContext 类中 DI 服务的默认实现(例如):

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.ReplaceService<Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure.IProviderConventionSetBuilder, TechnicalUtilities.CustomSqlServerConventionSetBuilder>(); }
或者,如果您想避免使此覆盖数据库提供程序特定,您也可以子类化 RuntimeConventionSetBuilder,覆盖 CreateConventionSet 方法,并将其注册到服务 IConventionSetBuilder。但该界面将来更有可能发生变化。

公约的实施情况可以在这里找到:

https://github.com/dotnet/efcore/blob/main/src/EFCore/Metadata/Conventions/ 该文档可以在这里找到: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.metadata.conventions?view=efcore-5.0

您应该检查特定约定实现了哪些“事件”,如果应抑制该约定,通常应将其从每个“事件”中删除。

这对于 EF Core 5.0 有效,在之前的版本中可能有所不同。您也可以查看

https://github.com/dotnet/efcore/issues/5737#issuecomment-225724598


0
投票
上述内容不适用于较新的 EF Core 版本,但您可以将

PropertyDiscoveryConvention

 替换为自定义版本,如以下 EF Core 示例所示:

https://learn.microsoft.com/en-us/ef/core/modeling/bulk-configuration#example-opt-in-property-mapping

这更改了仅包含显式定义的属性和标有自定义

[Persist]

 属性的方法。

© www.soinside.com 2019 - 2024. All rights reserved.