什么是 Entity Framework Core 属性等价于 modelBuilder 的 HasDefaultValueSql?

Posted

技术标签:

【中文标题】什么是 Entity Framework Core 属性等价于 modelBuilder 的 HasDefaultValueSql?【英文标题】:What is the Entity Framework Core attribute equivalent to modelBuilder's HasDefaultValueSql? 【发布时间】:2019-07-28 17:48:24 【问题描述】:

我想使用注解为我在 Entity Framework Core 中的属性设置默认值。问题是数据库没有设置默认值,因此该值没有被传递到数据库层。

我想做类似于modelBuilderHasDefaultValueSql的事情:

[DefaultValue("400")]
public int LengthInMeters get; set;

如何将下面的代码转换为属性?

modelBuilder.Entity<Patient>().Property(c => c.LengthInMeters).HasDefaultValueSql("400");

单独使用默认值是行不通的。我想单独使用属性而不必搞乱迁移。

问题:我用 EF 尝试了其他方法,但 Entity Framework Core 没有一些项目。比如modelBuilder.Conventions也不是AttributeToColumnAnnotationConvention也不是CSharpMigrationCodeGenerator也不是modelBuilder.Properties()

【问题讨论】:

You can not set a default value using Data Annotations 和 By convention, a default value is not configured @NaDeRStar 这正是我试图用属性替换的内容。 【参考方案1】:

This is what I ended up doing,如果有人有更清洁而不是密集的实施方式,请告诉我。

protected override void OnModelCreating(ModelBuilder modelBuilder)

    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    
        foreach (var property in entityType.GetProperties())
        
            var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
            if (memberInfo == null) continue;
            var defaultValue = Attribute.GetCustomAttribute(memberInfo, typeof(DefaultValueAttribute)) as DefaultValueAttribute;
            if (defaultValue == null) continue;                   
            property.SqlServer().DefaultValue = defaultValue.Value;
        
    
       

我可以使用默认值属性在数据库中设置默认值

[DefaultValue("400")]
public int LengthInMeters get; set;

【讨论】:

【参考方案2】:

使用 EF-Core 约定以另一种方式完成这项工作曾费了一番周折。我发现了一种添加所谓的“插件”的方法,它实现了IConventionSetPlugin 接口,您可以使用该接口添加自定义约定。它需要一些额外的代码来让 EntityFramework 使用插件。

但首先,让我们创建我们的PropertyAttributeConvention

public class DefaultValueAttributeConvention : PropertyAttributeConventionBase<DefaultValueAttribute>

    public DefaultValueAttributeConvention(ProviderConventionSetBuilderDependencies dependencies) : base(dependencies)  

    protected override void ProcessPropertyAdded(IConventionPropertyBuilder propertyBuilder, DefaultValueAttribute attribute,
        MemberInfo clrMember, IConventionContext context)
    
        propertyBuilder.HasDefaultValue(attribute.Value, fromDataAnnotation: true);
    

这里我们只是说 ef 属性构建器使用我们 [DefaultValue] 属性中定义的默认值。

要添加约定,我们需要创建一个自定义插件类:

public class CustomConventionSetPlugin : IConventionSetPlugin

    public ConventionSet ModifyConventions(ConventionSet conventionSet)
    
        conventionSet.PropertyAddedConventions.Add(new DefaultValueAttributeConvention(null));
        return conventionSet;
    

为了使用我们的插件,我们必须创建一个 ef 扩展类(它本身包含另一个 ExtensionInfo 类)

public class CustomDbContextOptionsExtension : IDbContextOptionsExtension

    public void ApplyServices(IServiceCollection services)
    
        services.AddSingleton<IConventionSetPlugin, CustomConventionSetPlugin>();
    

    public void Validate(IDbContextOptions options)  

    public DbContextOptionsExtensionInfo Info => new CustomDbContextOptionsExtensionInfo(this);

    private class CustomDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
    
        public CustomDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension)  

        public override long GetServiceProviderHashCode() => 0;

        public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)  

        public override bool IsDatabaseProvider => false;
        public override string LogFragment => "";
    

在扩展类中,我们将插件类添加到 EF-ServiceCollection

最后一步是转到我们的DbContext 并添加我们的扩展程序。这可以在OnConfigure 方法中完成:

public class MyDatacontext : DbContext

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    
        ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(new CustomDbContextOptionsExtension());
    

现在[DefaultValue] 属性可以用于我们的实体属性。 如果我们想添加不同的自定义约定,我们不必再次创建所有扩展/插件类。只需创建一个新的约定类并通过我们现有的插件类将其添加到convetionSet

【讨论】:

【参考方案3】:

安装Microsoft.EntityFrameworkCore.Relational 包,它应该可以解决您迁移到 EF 核心时的大部分迁移问题。

【讨论】:

以上是关于什么是 Entity Framework Core 属性等价于 modelBuilder 的 HasDefaultValueSql?的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework Core 快速开始

什么是 Entity Framework Core 属性等价于 modelBuilder 的 HasDefaultValueSql?

EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?

Entity Framework Core中更改跟踪工作原理

Entity Framework Core中更改跟踪工作原理

Entity Framework Core 不会更新 ICollection