我想使用注释为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
也不AttributeToColumnAnnotationConvention
或CSharpMigrationCodeGenerator
答案 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 核心时的大部分迁移问题。