【发布时间】:2014-12-30 23:25:25
【问题描述】:
我在 TPH 布局中使用 Entity Framework Code First。我的 DbSet 引用基(抽象)类,然后我对派生类进行操作。 EF 注意到这一点并自动在表中生成一个 Discriminator 字段。然后,我想根据子类以特定方式初始化属性。我目前在子类的构造函数中这样做。
这一切都非常适合保存到数据库。但是,当检索数据时,子构造函数在数据加载之前运行,导致构造函数逻辑和数据库结果都显示在目标集合中。
public abstract class Indicator
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Annotation> Annotations { get; set; }
protected Indicator()
{
Annotations = new List<Annotation>();
}
}
public class MyIndicator : Indicator
{
public MyIndicator()
{
Annotations = new List<Annotation>
{
new MyAnnotation() { Name = "First" },
new MyAnnotation() { Name = "Second" },
new MyAnnotation() { Name = "Third" }
};
}
}
public abstract class Annotation
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyAnnotation : Annotation {}
在数据库中填充一条记录后,尝试检索它会导致构造函数 Annotations 和数据库中的 Annotation 对象都显示在集合中。
Indicator newI = new MyIndicator { Name = "Custom collection" };
int count = 0;
var names = new List<string> { "Test 1", "Test 2", "Test 3" };
foreach (var a in newI.Annotations)
{ // overwite properties from "default" collection
a.Name = names[count++];
}
context.Indicators.Add(newI);
context.SaveChanges();
跑步:var i = context.Indicators.Single(x => x.Id == 1);
返回:
Annotations = {
[0] { Id = 0, Name = "First" } // constructor
[1] { Id = 0, Name = "Second" }
[2] { Id = 0, Name = "Third" }
[3] { Id = 1, Name = "Test 1" } // database entries
[4] { Id = 2, Name = "Test 2" }
[5] { Id = 3, Name = "Test 3" }
}
这种行为看起来很奇怪,我唯一能想到的是派生类的构造函数被延迟加载集合所需的 EF 代理以某种方式调用。
这是我正在处理的问题域的一个非常简化的版本。最终目标是在基于派生指标类的指标集合内初始化不同类型(派生类)的注释。然后,工厂或服务将使用 Annotation 派生类中的这些“默认”值填充模型的其他属性,以从应用程序外部选择数据。
更新/更多信息
我的意图是将所有内容存储在数据库中。但是,集合中派生类型的类型和数量对于派生类来说是唯一的。
示例: 假设我有一个 Car 抽象类和一些派生类:Sedan、Truck、Van。 Car 抽象类也有一个 Collection of Parts;另一个具有自己的包含“定义”的派生类集的抽象类。当我将 Truck 传递给我的工厂方法时,我希望根据类型使用默认值操作一辆新车:Truck。
class abstract Car
{
ICollection<Part> Parts { get; set; }
decimal Cost { get { return Parts.Sum(c => c.Cost) ?? 0; } }
}
class Truck : Car {
public Truck() {
Parts = new ICollection<Parts> {
new SteeringWheel(),
new Flatbed()
}
}
}
class abstract Part {
string Material { get; set; }
decimal Cost { get; set; }
}
class SteeringWheel : Part {
public SteeringWheel() { Material = "Polyurethane"; }
}
class Flatbed : Part {
public Part() { Material = "Steel"; }
}
当我在工厂新建一辆卡车时,我的零件系列包含一个由钢制成的平板和一个由聚氨酯制成的 SteeringWheel。然后我可以遍历新集合以查询外部源并返回每个项目的成本以填充其成本属性。轿车可能有 SteeringWheel 和 SunRoof,而厢式货车可能有 SteeringWheel、CargoDoor 和 TowHitch。
如果不使用特定的派生类型初始化零件列表,我将不得不将所有这些信息编码到工厂本身中。随着层的增加,这变得相当笨拙。 (想象一辆车,它有一个 Part 集合,一个 Material 集合,又包含 Quantity 和 Dimension 集合。)
【问题讨论】:
-
我认为您必须选择:持久化 或 硬编码列表。为什么不将all 列表项存储在数据库中?我不明白你什么时候需要哪些物品,但混合它们似乎是一个非常糟糕的主意。例如:您还必须防止硬编码的项目被持久化。
-
我更新了这篇文章,希望能澄清一点。
标签: asp.net linq entity-framework