ASP.从未映射的类中删除鉴别符列
本文关键字:删除 鉴别 映射 ASP | 更新日期: 2023-09-27 18:07:28
我有一个内容模型:
class BaseModel {
public virtual string Content{ get; set; }
// ...
}
只显示上面模型的数据就可以了。但是我想添加编辑内容的功能。因此,我需要向成员content添加一个属性,但这应该只发生在编辑器按下编辑按钮时,而不是在内容的常规视图中。
所以我创建了第二个模型,它继承了BaseModel,这样我就可以用我的属性覆盖成员:class EditableBaseModel : BaseModel {
[UIHint("MyEditor"), AllowHtml]
public override string Content{ get; set; }
}
这很好,但是由于继承EF创建了一个额外的列标识符。它包含类的类型为字符串。在我的情况下,它总是BaseModel因为我总是将EditableBaseModel转换为BaseModel在它被保存到数据库之前,像这样:
myBbContextInstance.BaseModels.Add(editableBaseModelInstance as EditableBaseModel);
因此,鉴别符列是浪费空间,我想删除它。我发现这可以使用notmapped属性来完成。但是,当我尝试保存模型时,这会导致以下异常:
无法为EntityType 'EditableBaseModel'找到映射和元数据信息。
似乎notmapped -属性会让EF知道存在另一个继承自BaseModel的类,但是EF不会得到关于这个类的任何信息。但那不是我想要的。我需要告诉EF: EditableBaseModel是什么都不应该关心,因为它只适合我的视图,并且永远不会用于数据库。
我该怎么做呢?我发现的唯一方法是将EditableBaseModel实例手动转换为BaseModel对象,如下所示:
public ActionResult Save(EditableBaseModel editableBaseModel) {
var baseModel = new BaseModel() {
Content = editableBaseModel.Content
// ...
};
myDbContextInstance.BaseModels.Add(baseModel);
}
但这似乎不是一个好方法,因为我有多个属性。它也不是很灵活因为当我向BaseModel添加一些东西时,我还需要在这里添加-这会导致奇怪的错误。
将EF
概念与MVC
概念混合到Model
中可能不适合两者。在本例中,创建新的BaseModel
并将EditableBaseModel
的内容复制到BaseModel
中,这是正确的方法。您可以使用AutoMapper在两个模型之间映射数据。
class EditableBaseModel
{
[UIHint("MyEditor"), AllowHtml]
public string Content{ get; set; }
}
public ActionResult Save(EditableBaseModel editableBaseModel) {
var baseModel = new BaseModel();
Mapper.Map<EditableBaseModel, BaseModel>(editableBaseModel, baseModel);
myDbContextInstance.BaseModels.Add(baseModel);
.
.
.
}
底线是,在实体框架中使用继承,你不能用两种不同的类型来表示数据库中的同一条记录。
换句话说,如果以任何方式使用继承,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
s则可以通过
myBbContextInstance.Database.SqlQuery<BaseModel>("SELECT * FROM dbo.BaseModel");
当然,查询可以参数化以过滤模型。BaseModel
不会被上下文跟踪,但是因为您只想显示它们,所以没有必要这样做。这是我看到的用另一种类型表示(某种程度上)数据库中的一条记录的唯一方法。
虽然我提到了技术上的可能性,但这并不意味着我推荐它。但是,即使对于可编辑选项,我也更喜欢使用视图模型。我不喜欢这种数据层和UI之间的紧密耦合
您是否考虑过在BaseModel
中使用构造函数,其工作方式如下:
public BaseModel(EditableBaseModel editableBaseModel) {
this.Content = editableBaseModel.Content
}
,并像这样使用:
myBbContextInstance.BaseModels.Add(new BaseModel(editableBaseModelInstance));