c# - asp net mvc tutorial




Entity Framework 5レコードの更新 (5)

あなたは探している:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

私は、ASP.NET MVC3環境でEntity Framework 5内のレコードを編集/更新するさまざまな方法を模索してきましたが、今まで必要なすべてのボックスをチェックすることはありませんでした。 理由を説明します。

私は賛否両論に言及する3つの方法を見つけました:

方法1 - 元のレコードをロードし、各プロパティを更新する

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

長所

  • 変更するプロパティを指定できます
  • ビューにすべてのプロパティを含める必要はありません

短所

  • データベースを2回クエリして元のデータを読み込んで更新する

方法2 - 元のレコードをロードし、変更された値を設定する

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

長所

  • 変更されたプロパティのみがデータベースに送信されます。

短所

  • ビューにはすべてのプロパティを含める必要があります
  • データベースを2回クエリして元のデータを読み込んで更新する

方法3 - 更新されたレコードを添付し、状態をEntityStateに設定します。

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

長所

  • 1 x更新するデータベースのクエリ

短所

  • 変更するプロパティを指定することはできません
  • ビューはすべてのプロパティを含む必要があります

質問

あなたに私の質問; この目標を達成するためのきれいな方法はありますか?

  • 変更するプロパティを指定できます
  • ビューには、すべてのプロパティ(パスワードなど)を含む必要はありません。
  • 1 x更新するデータベースのクエリ

私はこれが非常に小さなことを指摘していることを理解していますが、私はこれに対する単純な解決策を見逃しているかもしれません。 メソッドではない場合は勝つ;-)


オプションのリストに追加するだけです。 データベースからオブジェクトを取得し、 Auto Mapperのような自動マッピングツールを使用して、変更したいレコードの部分を更新することもできます。


リポジトリの基本クラスに追加の更新メソッドを追加しました。これは、Scaffoldingによって生成された更新メソッドに似ています。 オブジェクト全体を「変更」に設定する代わりに、個々のプロパティのセットを設定します。 (Tはクラスジェネリックパラメータです。)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

そして、たとえば、次のように呼び出します。

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

私はデータベースへの1回の旅行が好きです。 ただし、一連のプロパティの繰り返しを避けるため、ビューモデルでこれを行う方がよいでしょう。 ビューモデルバリデーターの検証メッセージを私のドメインプロジェクトに持ち込まないようにする方法がわからないので、私はまだそれをしていません。


私は受け入れられた答えが本当に好きです。 私はこれにもアプローチするもう一つの方法があると信じています。 たとえば、ビューに含めたくないプロパティのリストが非常に短いとします。そのため、エンティティを更新するときは省略されます。 その2つのフィールドがパスワードとSSNであるとしましょう。

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

この例では、Usersテーブルとビューに新しいフィールドを追加した後、基本的にビジネスロジックをそのままにしておくことができます。


public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}




entity-framework-5