我想减少重复的代码,为多个对象和关联的数据库表中使用的对象属性指定相同的属性。
我正在使用属性属性来定义如何在数据库中保存属性以及如何在UI元素中标题。在我的情况下,此属性出现在多个表/对象中,我希望它在任何地方都具有相同的属性。我还希望这些属性能够被Entity Framework的代码首次迁移所吸引。看起来代码首次迁移在属性上循环,并查找特定类,如MaxLengthAttribute或从特定类继承的类。太糟糕了,实体框架并不寻找接口。
我不想将此字符串移动到其他表格,因为将使用这些表格的客户希望它们能够被" CustomerNo"直接查询。
例如:
[Table("foo")]
public class foo {
…
[Column(TypeName="varchar")]
[MaxLength(15)]
[Display(Name="Customer Identifier")]
public string CustomerNo {get; set;}
…
}
[Table("bar")]
public class bar {
…
[Column(TypeName="varchar")]
[MaxLength(15)]
[Display(Name="Customer Identifier")]
public string CustomerNo {get; set;}
…
}
我想要做的是创建一个自定义属性,将上述属性组合成一个像[CustomerNoAttribute](我知道我可以省略后缀"属性"它可以减少混淆class CustomerNo)。
没有多重继承,所以我不能只继承ColumnAttribute,MaxLengthAttribute和DisplayAttribute。
有没有办法可以使用合成来完成这项工作? e.g。
以下代码不起作用。新的内部属性未附加到我放置[CustomerNoAttribute]的属性。
public CustomerNoAttribute: Attribute {
public CustomerNoAttribute() {
new MaxLengthAttribute(15);
new DisplayAttribute().Name = "Customer Identifier";
new ColumnAttribute().TypeName = "nvarchar";
}
}
还有另一种方法可以减少这种重复吗?
使用运行时添加属性的技术不会有帮助,因为它看起来像实体框架的代码第一次迁移仅查看编译时属性。
答案 0 :(得分:2)
这里的解决方案相对简单,是我最喜欢的实体框架功能之一:
代码优先约定
See Custom Code First Conventions作完整介绍,其概念是您可以定义EF运行时应遵循的任意规则或惯例,这可能基于属性,但这不是必须的。如果您确实需要,可以根据字段名称的后缀或前缀创建约定。
自定义公约与自定义类型描述符类似,如解决方案https://stackoverflow.com/a/38504552/1690217中所述,除了专门针对实体框架代码优先模型
您处在正确的轨道上,创建自定义属性可简化自定义代码约定的实现,但是Display属性是有问题的...通常,我建议从提供最多配置的属性中进行继承,在这种情况下,{{1} },但是我们无法继承该类型,因为它是密封的。
不幸的是,我将DisplayAttribute
排除在此解决方案之外,因为在消费者端可以采用不同的约定概念。而是显示了如何使用自定义属性来替换多个基于DisplayAttribute
的 Attributes 。
DataAnnotation
现在可以在您的课程中使用自定义属性:
public CustomerNoAttribute : Attribute {
}
public class CustomerNoConvention : Convention
{
public CustomerNoConvention()
{
this.Properties()
.Where(p => p.GetCustomAttributes(false).OfType<CustomerNoAttribute>().Any()
.Configure(c => c.HasColumnType("nvarchar")
.HasMaxLength(15)
);
}
}
最后,我们必须启用自定义约定,我们可以通过在您的[Table("foo")]
public class foo {
…
[CustomerNo]
[Display(Name="Customer Identifier")]
public string CustomerNo {get; set;}
…
}
[Table("bar")]
public class bar {
…
[CustomerNo]
[Display(Name="Customer Identifier")]
public string CustomerNo {get; set;}
…
}
类中覆盖OnModelCreating
来做到这一点:
DbContext
减少多个属性和约定的重复条目的另一种解决方案当然是使用继承:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new CustomerNoConvention());
}