1

asp.net mvc4 アプリを作成しており、エンティティ フレームワーク 5 を使用しています。各エンティティには、、、、などのフィールドEnteredByEnteredOnありLastModifiedByますLastModifiedOn

SavingChangesイベントを使用して自動保存しようとしています。以下のコードは、多数のブログ、SO 回答などからまとめられています。

public partial class myEntities : DbContext
{
    public myEntities()
    {            
        var ctx = ((IObjectContextAdapter)this).ObjectContext;
        ctx.SavingChanges += new EventHandler(context_SavingChanges);
    }

    private  void context_SavingChanges(object sender, EventArgs e)
    {

        ChangeTracker.DetectChanges();

        foreach (ObjectStateEntry entry in
                 ((ObjectContext)sender).ObjectStateManager
                   .GetObjectStateEntries
                    (EntityState.Added | EntityState.Modified))
        {         
            if (!entry.IsRelationship)
            {
                CurrentValueRecord entryValues = entry.CurrentValues;               

                if (entryValues.GetOrdinal("LastModifiedBy") > 0)
                {
                    HttpContext currContext = HttpContext.Current;
                    string userName = "";
                    DateTime now = DateTime.Now;

                    if (currContext.User.Identity.IsAuthenticated)
                    {
                        if (currContext.Session["userId"] != null)
                        {
                            userName = (string)currContext.Session["userName"];
                        }
                        else
                        {
                            userName = currContext.User.Identity.Name;
                        }
                    }

                    entryValues.SetString(
                      entryValues.GetOrdinal("LastModifiedBy"), userName);
                    entryValues.SetDateTime(
                      entryValues.GetOrdinal("LastModifiedOn"), now);

                    if (entry.State == EntityState.Added)
                    {
                        entryValues.SetString(
                          entryValues.GetOrdinal("EnteredBy"), userName);
                        entryValues.SetDateTime(
                          entryValues.GetOrdinal("EnteredOn"), now);
                    }
                    else
                    {                
                     string enteredBy = 
                  entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"));
                     DateTime enteredOn =
entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"));

                        entryValues.SetString(
                       entryValues.GetOrdinal("EnteredBy"),enteredBy);
                        entryValues.SetDateTime(
                        entryValues.GetOrdinal("EnteredOn"), enteredOn);

                    }
                }
            }
        }
    }
}

私の問題は、元の値entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"))entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"))はなく、現在の値を返すことですnull。エンティティの他のフィールドでテストしたところ、html フォームに入力された現在の値が返されています。

ここで元の値を取得するにはどうすればよいですか?

4

2 に答える 2

5

モデル バインダーによって提供されるインスタンスをコントローラー メソッドへの入力として使用しているため、EF はそのエンティティとその元の状態について何も知らないことが問題である可能性があると思います。コードは次のようになります。

public Review Update(Review review)
{
    _db.Entry(review).State = EntityState.Modified;
    _db.SaveChanges();
    return review;
}

Reviewその場合、EFは保存されているインスタンスについて何も知りません。あなたを信頼し、変更済みとして設定しているため、すべてのプロパティをデータベースに保存しますが、そのエンティティの元の状態\値はわかりません。

Entity Statesという名前のセクションと、このチュートリアルの Attach メソッドと SaveChanges メソッドを確認してください。この記事の最初の部分を確認することもできます。これは、EF が元の値を認識せず、データベース内のすべてのプロパティを更新する方法を示しています。

EF は元のプロパティについて知る必要があるため、最初にエンティティをデータベースからロードしてから、コントローラーで受け取った値でそのプロパティを更新することができます。このようなもの:

public Review Update(Review review)
{
    var reviewToSave = _db.Reviews.SingleOrDefault(r => r.Id == review.Id);
    //Copy properties from entity received in controller to entity retrieved from the database
    reviewToSave.Property1 = review.Property1;
    reviewToSave.Property2 = review.Property2;
    ...

    _db.SaveChanges();
    return review;
}

これには、変更されたプロパティのみがデータベースで送信および更新され、ビューとビュー モデルがビジネス オブジェクトのすべてのフィールドを公開する必要がなく、ユーザーが更新できるフィールドのみを公開するという利点があります。(viewModels と models\business オブジェクトの異なるクラスを持つための扉を開く)。明らかな欠点は、データベースへの追加のヒットが発生することです。

上記で参照したチュートリアルで言及されている別のオプションは、元の値を何らかの方法で保存し (隠しフィールド、セッションなど)、保存時に元の値を使用して、エンティティを変更されていない状態でデータベース コンテキストにアタッチすることです。次に、編集したフィールドでそのエンティティを更新します。ただし、その追加のデータベース ヒットを本当に回避する必要がない限り、このアプローチはお勧めしません。

それが役立つことを願っています!

于 2013-09-02T08:24:26.027 に答える