885

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.Modified に設定する

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

長所

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

短所

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

質問

皆さんへの質問です。この一連の目標を達成できるクリーンな方法はありますか?

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

これは指摘するのは非常に些細なことだと理解していますが、これに対する簡単な解決策を見逃している可能性があります。そうでない場合は、方法が優先されます;-)

4

8 に答える 8

684

あなたは探している:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();
于 2013-03-11T13:12:34.607 に答える
176

私は受け入れられた答えが本当に好きです。これにアプローチする別の方法もあると思います。ビューに含めたくないプロパティの非常に短いリストがあるとします。そのため、エンティティを更新するとき、それらは省略されます。これらの 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();   

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

于 2013-08-01T21:01:38.323 に答える
28
foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();
于 2013-11-12T11:33:31.747 に答える
24

Scaffolding によって生成された update メソッドに似た、追加の update メソッドをリポジトリ基本クラスに追加しました。オブジェクト全体を「変更済み」に設定する代わりに、個々のプロパティのセットを設定します。(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 回の旅行が好きです。ただし、プロパティのセットの繰り返しを避けるために、ビュー モデルでこれを行う方がよいでしょう。ビューモデルバリデーターの検証メッセージをドメインプロジェクトに持ち込まないようにする方法がわからないため、まだ行っていません。

于 2015-04-25T16:19:49.580 に答える
3

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

于 2015-12-03T15:58:36.417 に答える
3

ユースケースに応じて、上記のすべてのソリューションが適用されます。ただし、これは私が通常行う方法です:

サーバー側のコード (バッチ プロセスなど) では、通常、エンティティをロードして動的プロキシを操作します。通常、バッチ プロセスでは、サービスの実行時にとにかくデータをロードする必要があります。時間を節約するために、find メソッドを使用する代わりに、データをバッチ ロードしようとしています。プロセスに応じて、楽観的または悲観的な同時実行制御を使用します (単純な sql ステートメントでいくつかのレコードをロックする必要がある並列実行シナリオを除いて、私は常に楽観的を使用しますが、これはまれです)。コードとシナリオによっては、影響をほぼゼロに減らすことができます。

クライアント側のシナリオでは、いくつかのオプションがあります

  1. ビュー モデルを使用します。モデルにはプロパティ UpdateStatus(unmodified-inserted-updated-deleted) が必要です。ユーザーのアクション (挿入-更新-削除) に応じて、この列に正しい値を設定するのはクライアントの責任です。サーバーはデータベースに元の値を照会するか、クライアントが変更された行とともに元の値をサーバーに送信する必要があります。サーバーは元の値を添付し、各行の UpdateStatus 列を使用して新しい値の処理方法を決定する必要があります。このシナリオでは、常にオプティミスティック コンカレンシーを使用します。これは挿入 - 更新 - 削除ステートメントのみを実行し、選択は実行しませんが、グラフをたどってエンティティを更新するための巧妙なコードが必要になる場合があります (シナリオ - アプリケーションによって異なります)。マッパーは役に立ちますが、CRUD ロジックを処理しません

  2. (1 で説明したように) この複雑さのほとんどを隠蔽する、breast.js のようなライブラリを使用して、それをユース ケースに適合させてみてください。

それが役に立てば幸い

于 2016-05-30T12:07:46.630 に答える