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

时间:2019-03-06 23:12:50

标签: c# attributes entity-framework-core custom-data-attribute

我想使用注释为Entity Framework Core中的属性设置默认值。问题在于数据库未设置默认值,因此该值未向下传递到数据库层。

我想做类似于modelBuilder的{​​{1}}的事情:

HasDefaultValueSql

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

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

单独使用默认值不起作用。我想单独使用属性,而不必弄乱迁移。

问题:我已经尝试使用EF进行其他方法,但是Entity Framework Core没有某些项目。例如modelBuilder.Entity<Patient>().Property(c => c.LengthInMeters).HasDefaultValueSql("400"); modelBuilder.Conventions也不AttributeToColumnAnnotationConventionCSharpMigrationCodeGenerator

3 个答案:

答案 0 :(得分:1)

在使用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 propertybuilder使用在[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

答案 1 :(得分:0)

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 :(得分:0)

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