我有一个我的内容模型:
0.0
要仅显示数据,上面的模型就可以了。但我想添加编辑内容的功能。所以我需要为成员内容添加一个属性 - 但这只应该在autor按下编辑按钮时发生,而不是在内容的常规视图中。
所以我创建了第二个继承自 BaseModel 的模型,以便我可以用我的属性覆盖该成员:
class BaseModel {
public virtual string Content{ get; set; }
// ...
}
这样可以正常工作,但由于继承,EF会创建一个额外的列鉴别器。它包含类的类型作为字符串。在我的情况下,它总是 BaseModel ,因为我总是将 EditableBaseModel 转换为 BaseModel ,然后将它保存到数据库中,如下所示:
class EditableBaseModel : BaseModel {
[UIHint("MyEditor"), AllowHtml]
public override string Content{ get; set; }
}
因此,鉴别器列是浪费空间,我想删除它。我发现这可以完成using the NotMapped-attribute。但是当我尝试保存模型时,这将导致以下异常:
无法找到EntityType'EditableBaseModel'的映射和元数据信息。
似乎NotMapped属性会让EF知道存在继承自 BaseModel 的另一个类,但EF不会获得有关此类的任何信息。但那不是我想要的。我需要告诉EF: EditableBaseModel 没什么值得关注的,因为它只适合我的观点,并且永远不会用于数据库。
我该怎么做?我发现的唯一方法是手动将 EditableBaseModel 实例转换为 BaseModel 对象,如下所示:
myBbContextInstance.BaseModels.Add(editableBaseModelInstance as EditableBaseModel);
但这似乎不是一个很好的方法,因为我有多重属性。而且它也不是很灵活,因为当我向BaseModel添加内容时,我还必须在这里添加它 - 这可能会导致奇怪的错误。
答案 0 :(得分:4)
最重要的是,使用Entity Framework中的继承,您无法通过两种不同类型在数据库中表示相同的记录。
换句话说,如果以任何方式使用继承,EF可以将数据库中的任何行实现为仅一种类型。所以你想要的东西永远不可能,有或没有鉴别器。
我认为EditableBaseModel
之间的转换是可行的选择。或者将BaseModel
包装在EditableBaseModel
中,后者具有委托属性,如
public string Content
{
[UIHint("MyEditor"), AllowHtml]
get { return _baseModel.Content; }
set { _baseModel.Content = value; }
}
这是一种常见的模式,称为 Decorator 。请注意,在这种情况下(或转换),您不应将EditableBaseModel
注册为EF模型中的实体。
从技术上讲,另一种方法是可行的。您可以通过DbContext.Database.SqlQuery
实现任何对象。您可以仅将BaseModel
用于显示目的,并使用EditableBaseModel
作为映射的实体类。 BaseModel
然后,可以通过
myBbContextInstance.Database.SqlQuery<BaseModel>("SELECT * FROM dbo.BaseModel");
当然可以对查询进行参数化以过滤模型。上下文不会跟踪BaseModel
,但由于您只想显示它们,因此没有必要。这是我看到用另一种类型表示(排序)数据库中的一条记录的唯一方法。
虽然我提到了技术可能性,但这并不意味着我推荐它。但是,即使对于可编辑选项,我也更喜欢使用视图模型。我不喜欢数据层和UI之间的紧密耦合。
答案 1 :(得分:1)
您是否考虑在BaseModel
中使用构造函数,该构造函数按以下方式工作:
public BaseModel(EditableBaseModel editableBaseModel) {
this.Content = editableBaseModel.Content
}
并像这样使用它:
myBbContextInstance.BaseModels.Add(new BaseModel(editableBaseModelInstance));