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

时间:2017-04-20 06:30:47

标签: c# entity-framework entity-framework-core

EF Core(与之前的EF一样)会自动将properties with a get/set添加到模型中。

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

我希望EF只包含我配置的属性。

如何禁用此约定?

1 个答案:

答案 0 :(得分:4)

在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://docs.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