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添加一些东西时,我还需要在这里添加-这会导致奇怪的错误。

ASP.从未映射的类中删除鉴别符列

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