14

私は自分のコンテンツのモデルを持っています:

class BaseModel {
    public virtual string Content{ get; set; }
    // ...
}

データのみを表示するには、上記のモデルで問題ありません。しかし、コンテンツを編集する機能を追加したいと考えています。したがって、メンバーコンテンツに属性を追加する必要があります-しかし、これは、コンテンツの通常のビューではなく、作成者が編集ボタンを押したときにのみ発生するはずです。

そこで、 BaseModelから継承する 2 番目のモデルを作成して、メンバーを自分の属性でオーバーライドできるようにしました。

class EditableBaseModel : BaseModel {
    [UIHint("MyEditor"), AllowHtml]
    public override string Content{ get; set; }
}

これは正常に機能しますが、継承のため、EF は追加の column discriminatorを作成します。クラスの型が文字列として含まれています。私の場合、次のようにデータベースに保存される前に、常にEditableBaseModelBaseModelに変換するため、常にBaseModelです。

myBbContextInstance.BaseModels.Add(editableBaseModelInstance as EditableBaseModel);

したがって、discriminator-column はスペースの無駄であり、削除したいと考えています。これは NotMapped-attribute を使用して実行できることがわかりました。ただし、モデルを保存しようとすると、次の例外が発生します。

EntityType 'EditableBaseModel' のマッピングおよびメタデータ情報が見つかりませんでした。

NotMapped-attribute は、 BaseModel から継承する別のクラスが存在することを EF に知らせるようですが EF はこのクラスに関する情報を取得しません。しかし、それは私が望むものではありません。EF に伝える必要があります。EditableBaseModelは、私のビューに適合するだけで、データベースには使用されないため、気にする必要はありません。

どうやってやるの?私が見つけた唯一の方法は、次のようにEditableBaseModelインスタンスを手動でBaseModelオブジェクトに変換することです。

public ActionResult Save(EditableBaseModel editableBaseModel) {
    var baseModel = new BaseModel() {
        Content = editableBaseModel.Content
        // ...
    };
    myDbContextInstance.BaseModels.Add(baseModel);
}

しかし、複数の属性があるため、これは良い方法ではないようです。また、BaseModel に何かを追加するときに、ここにも追加する必要があるため、あまり柔軟ではありません。奇妙なエラーが発生する可能性があります。

4

3 に答える 3

8

EF概念とMVC概念を混合して に入れるとModel、両方に適合しない場合があります。この場合、新しいものを作成し、あなたがしたようBaseModelにの内容をにコピーするのが正しい方法です。AutoMapperを使用して、2 つのモデル間でデータをマッピングできます。EditableBaseModelBaseModel

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);
    .
    .
    .
}
于 2015-08-15T04:41:02.937 に答える
4

つまり、Entity Framework で継承を使用すると、データベース内の同じレコードを 2 つの異なる型で表すことはできません

別の言い方をすれば、何らかの方法で継承を使用する場合、EF はデータベース内の任意の行を 1 つの型のみに実体化できます。したがって、弁別器の有無にかかわらず、あなたが望むことは決して不可能です。

との間の変換は実行可能なオプションだと思いEditableBaseModelます。BaseModelまたは、 aを a でラップしEditableBaseModelます。後者には、次のようなデリゲート プロパティがあります。

public string Content
{ 
    [UIHint("MyEditor"), AllowHtml]
    get { return _baseModel.Content; }
    set { _baseModel.Content = value; }
}

これはDecoratorと呼ばれる一般的なパターンです。EditableBaseModelその場合 (または変換した場合) 、EF モデルにエンティティとして登録しないでください。

技術的には、別のアプローチが可能です。によって任意のオブジェクトを具体化できますDbContext.Database.SqlQueryBaseModel表示目的でのみ使用EditableBaseModelし、マップされたエンティティ クラスとして使用できます。BaseModelその場合、次のように具体化できます

myBbContextInstance.Database.SqlQuery<BaseModel>("SELECT * FROM dbo.BaseModel");

もちろん、クエリをパラメータ化してモデルをフィルタリングできます。はBaseModelコンテキストによって追跡されませんが、それらを表示するだけなので、それは必要ありません。これは、データベース内の 1 つのレコードを別のタイプで (一種の) 表現する唯一の方法です。

技術的な可能性について言及していますが、それは私が推奨するという意味ではありません。ただし、編集可能なオプションであっても、ビューモデルを使用することをお勧めします。私は、データ層と UI の間のこの密結合が好きではありません。

于 2015-08-18T22:50:39.897 に答える
1

BaseModel次のように機能するコンストラクターの使用を検討しましたか。

public BaseModel(EditableBaseModel editableBaseModel) {
    this.Content = editableBaseModel.Content
}

次のように使用します。

myBbContextInstance.BaseModels.Add(new BaseModel(editableBaseModelInstance));
于 2015-08-15T03:31:14.210 に答える