gpt4 book ai didi

c# - 可以制作一个 C# 属性,该属性是 Entity Framework 代码首次迁移获取的其他属性的组合

转载 作者:太空狗 更新时间:2023-10-29 21:56:23 24 4
gpt4 key购买 nike

我想减少重复代码,其中我为多个对象和关联数据库表中使用的对象属性指定了相同的属性。

我正在使用属性特性来定义应如何将属性保存在数据库中以及应如何在 UI 元素中为其命名。在我的例子中,这个属性出现在多个表/对象中,我希望它在任何地方都具有相同的属性。我还希望 Entity Framework 的代码优先迁移能够获取这些属性。看起来代码优先迁移循环遍历属性并查找特定类,如 MaxLengthAttribute 或从特定类继承的类。太糟糕了, Entity Framework 不寻找接口(interface)。

我不想将这个字符串移到不同的表中,因为将要使用这些表的客户希望他们直接通过“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] 之类的属性(我知道我可以去掉后缀“Attribute”,它在那里可以减少类 CustomerNo 的混淆)。

没有多重继承,所以我不能只继承 ColumnAttribute、MaxLengthAttribute 和 DisplayAttribute。

有没有一种方法可以使用合成来完成这项工作?例如

下面的代码不起作用。新的内部属性未附加到我放置 [CustomerNoAttribute] 的属性。

public CustomerNoAttribute: Attribute {

public CustomerNoAttribute() {
new MaxLengthAttribute(15);
new DisplayAttribute().Name = "Customer Identifier";
new ColumnAttribute().TypeName = "nvarchar";
}
}

还有其他方法可以减少这种重复吗?

使用运行时添加属性的技术不会有帮助,因为它看起来像 Entity Framework 的代码优先迁移只查看编译时属性。

最佳答案

这里的解决方案相对简单,也是我最喜欢的 Entity Framework 特性之一:

Code First Conventions

See Custom Code First Conventions for a full run through, the concept is that you can define your own arbitrary rules or conventions that the EF runtime should obey, this might be based on attributes but it doesn't have to be. You could create a convention based on the suffix or prefix on a field name if you really wanted.

Custom Conventions is a similar mechanism to Custom Type Descriptors as explained in this solution https://stackoverflow.com/a/38504552/1690217, except specifically for Entity Framework Code First models

你走在正确的轨道上,制作自定义属性简化了自定义代码约定的实现,然而 Display 属性是有问题的......通常我会建议从提供最多配置的属性继承,在这种情况下 DisplayAttribute ,但我们不能继承该类型,因为它是密封的。不幸的是,我将 DisplayAttribute 排除在该解决方案之外,因为在消费者端可以采用不同的约定概念。这反而展示了如何使用自定义属性替换多个基于 DataAnnotationAttributes

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;}

}

最后,我们必须启用自定义约定,我们可以通过覆盖 DbContext 类中的 OnModelCreating 来实现:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new CustomerNoConvention());
}

减少多个属性和约定的重复条目的替代解决方案当然是使用继承:

public abstract class HasCustomerNo {

[CustomerNo]
[Display(Name="Customer Identifier")]
public string CustomerNo {get; set;}

}
[Table("foo")]
public class foo : HasCustomerNo {

// no need for CustomerNo

}

[Table("bar")]
public class bar : HasCustomerNo {

// no need for CustomerNo

}

关于c# - 可以制作一个 C# 属性,该属性是 Entity Framework 代码首次迁移获取的其他属性的组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50457080/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com