ASP.NET EF从未映射的类中删除了鉴别器列

时间:2015-08-11 22:54:51

标签: c# asp.net entity-framework inheritance entity-framework-mapping

我有一个我的内容模型:

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添加内容时,我还必须在这里添加它 - 这可能会导致奇怪的错误。

2 个答案:

答案 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));