8

バックエンドロジックにEntityFrameworkを使用してMVCでWebアプリケーションを作成しています。私の問題は、更新時に変更してはならない特定のフィールドを持つエンティティがあることです。この問題を解決する最善の方法が何であるかはよくわかりません。私のアプリケーションでは大量のデータが処理されるため、ソリューションをハックするだけの余裕はありません。

POCOエンティティでフィールドを読み取り専用として定義することは可能ですか?または、すべての更新を検証するエンティティフレームワーク拡張クラスを作成する必要があります。EFと実際のデータベース間のマッピングファイルで実行できますか?

私はEFに比較的慣れていないので、あなたの何人かが私にいくつかの指針を与えることができるかもしれないことを願っています!

ありがとう!

4

2 に答える 2

15

.NET4.5およびEF5(つまり、MVC 4)を使用している場合は、問題の個々のプロパティにIsModified=falseを設定するだけです。これには、デフォルトのすぐに使用可能なMVC規則に近いという利点があります。

たとえば、レコードの更新時に触れてはならないCreatedByフィールドがある場合は、コントローラーで次を使用します。

[HttpPost]
    public ActionResult Edit(Response response)
    {
        if (ModelState.IsValid)
        {
            db.Entry(response).State = EntityState.Modified;
            db.Entry(response).Property(p => p.CreatedBy).IsModified = false;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(response);
    }

IsModified行は、デフォルトのコントローラーアクションからの唯一の変更であることに注意してください。

.State = EntityState.Modifiedを設定した後にこの行を配置する必要があります(これはレコード全体に適用され、レコードをdbコンテキストに追加します)。

その結果、EFはこの列をSQLUPDATEステートメントに含めません。

[ReadOnly]に似た[InsertOnly]または[UpdateOnly]属性がないことに、私はまだ(非常に)ショックを受けています。これは、MVCチームによる大きな見落としのようです。私は何かが足りないのですか?

この解決策はハックであるため、私は完全には満足していません。あなたが実際に言っているのが「HANDS OFF」の場合、変更は行われなかったとEFに伝えています。また、フィールドを更新できる場所であればどこでもこのコードを使用する必要があることも意味します。クラスプロパティに属性を設定することをお勧めします。

(古いスレッドに投稿して申し訳ありませんが、このソリューションは他のどこにも見当たりません。ViewModelsは堅牢ですが、多くの作業が必要です。EFは、物事を難しくするのではなく、簡単にするはずでした...)

于 2012-11-21T23:24:10.133 に答える
5

ビューでEFクラスを使用しないようにアドバイスします。最善の策は、ViewModelクラスを作成し、Automapperを使用してEFクラスからそれらをマップすることです。

ただし、データベースのレコードを更新する場合は、ViewModelのどのフィールドを使用してEFクラスの既存のフィールドを更新するかを制御できます。

通常のプロセスは次のとおりです。

  • Idを使用して、データベースから既存のオブジェクトの最新バージョンを取得します。

  • 楽観的同時実行制御を使用している場合は、ViewModelが作成されてからオブジェクトが更新されていないことを確認してください(たとえば、タイムスタンプを確認してください)。

  • このオブジェクトを、ViewModelオブジェクトの必須フィールドで更新します。

  • 更新されたオブジェクトをデータベースに永続化します。

Automapperの例を含めるように更新します。

あなたのPOCOが

public class MyObject 
{
   public int Id {get;set;}
   public string Field1 {get;set;}
   public string Field2 {get;set;}
}

Field1は、更新したくないフィールドです。

同じプロパティでビューモデルを宣言する必要があります。

public class MyObjectModel 
{
   public int Id {get;set;}
   public string Field1 {get;set;}
   public string Field2 {get;set;}
}

コントローラのコンストラクタでそれらの間を自動マップします。

Mapper.CreateMap<MyObject, MyObjectModel>();

必要に応じてできます(これは手動で行うことをお勧めしますが、他の方法でも自動マッピングします。

Mapper.CreateMap<MyObjectModel, MyObject>().ForMember(dest=>dest.Field1, opt=>opt.Ignore());

あなたがあなたのウェブサイトに日付を送るとき、あなたは使うでしょう:

 var myObjectModelInstance = Mapper.Map<MyObject, MyObjectModel>(myObjectInstance);

viewModelを作成します。

データを保存するときは、おそらく次のようなものが必要になります。

public JsonResult SaveMyObject(MyObjectModel myModel)
{
    var poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
    if(myModel.Id == 0 ) 
    {
       //New object
       poco.Field1 = myModel.Field1 //set Field1 for new creates only

    }
}

上記のField1の除外を削除して、次のようにします。

public JsonResult SaveMyObject(MyObjectModel myModel)
{
   var poco;
   if(myModel.Id == 0)
   {
     poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
   }        
   else
   {
     poco = myDataLayer.GetMyObjectById(myModel.Id);
     poco.Field2 = myModel.Field2;
   }
   myDataLayer.SaveMyObject(poco);
}

ベストプラクティスでは、ViewModelから自動マップすることは決してないだろうと思いますが、新しいアイテムを含め、常に手動でこれを行う必要があります。

于 2012-07-23T08:37:08.797 に答える