0

User エンティティ クラスがあります。

public class User
{
    [Key]
    public int UserId { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string SecretQuestion { get; set; }
    public string SecretAnswer { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public Nullable<byte> UserType { get; set; }
    public Nullable<bool> Enabled { get; set; }
    public Nullable<DateTime> Created { get; set; }
    public Nullable<DateTime> Modified { get; set; }

    public void LoadWCPModel(UserWCPModel model)
    {
        Username = model.Username;
        Password = model.Password;
        SecretQuestion = model.SecretQuestion;
        SecretAnswer = model.SecretAnswer;
        UserType = model.UserType;
        Enabled = model.Enabled;
    }
}

Web 構成ポータル (WCP) のモデル クラスがあります。

public class UserWCPModel
{
    [Key]
    public int UserId { get; set; }

    [Display(Name = "Username")]
    [Required]
    public string Username { get; set; }

    [Display(Name = "Password")]
    [Required]
    public string Password { get; set; }

    [Display(Name = "Secret question")]
    [Required]
    public string SecretQuestion { get; set; }

    [Display(Name = "Secret answer")]
    [Required]
    public string SecretAnswer { get; set; }

    [Display(Name = "User type")]
    [Required]
    public Nullable<byte> UserType { get; set; }

    [Display(Name = "Enabled")]
    [Required]
    public Nullable<bool> Enabled { get; set; }

    [ScaffoldColumn(false)]
    public Nullable<DateTime> Created { get; set; }

    [ScaffoldColumn(false)]
    public Nullable<DateTime> Modified { get; set; }

    /// Parameterless constructor for MVC model binder.
    public UserWCPModel()
    {
        Created = DateTime.UtcNow;
    }

}

目標: UserWCPModel を取得し、データベースからのデータのリロードを完全に回避しながら、他のアプリケーション (電子メール、電話、フルネーム) によって入力されたデータを損なうことなく、そのモデルからのデータのみを保存します。

まず、HttpPost Edit アクション:

    [HttpPost]
    public ActionResult Edit(UserWCPModel model)
    {
        if (ModelState.IsValid)
        {
            WrappedE result;
            repo.Update(model, out result);
            if (result.ErrorCode != ErrorCodes.Success)
            {
                /// Add error handling;
            }
            return RedirectToAction("Index");
        }
        return View(model);
    }

ご覧のとおり、UserWCPModel を渡すことによって、リポジトリからのみ Update メソッドを呼び出します。

ここにリポジトリメソッドがあります:

    public void Update(UserWCPModel model, out WrappedE result)
    {
        User user = new User();           
        user.UserId = model.UserId;        
        db.Users.Attach(user);
        user.LoadWCPModel(model);
        user.Modified = DateTime.UtcNow;
        SaveToDb(out result);
    }
  1. 空白の User オブジェクトを構築します。
  2. モデルから取得した ID を割り当てます。
  3. DbSet ユーザーに添付します。
  4. UserWCPModel から User オブジェクトにデータをロードします。
  5. 変更時間を設定しました(重要ではありません)。
  6. db.SaveChanges() を呼び出します (これが SaveToDb の機能です)。

目標達成!2 番目の SELECT クエリはありません。モデルに関係のない保存データはありません。すべてのプロパティに対して IsModified を呼び出す必要はありません。モデルの範囲外の以前に入力されたデータに害はありません。

私はそれをひどく微調整したので、ここで共有する必要があり、いくつかのコメントを期待しています:D

誰かがこれが役に立つことを願っています:)

4

1 に答える 1

1

このメソッドをエンティティの更新に使用している場合は、十分に注意する必要があります。同じコンテキストで同じエンティティを 2 回更新しようとするとどうなるかを簡潔に説明します。(ネタバレ: 既にアタッチされているエンティティをアタッチしようとすると、例外が発生します)

さらに、すべてのクエリに ( AsNoTracking に関する私のブログ投稿を.AsNoTracking()参照) を追加して、実際に更新を実行するまで読み取り専用エンティティを操作することをお勧めします。これは、エンティティをコンテキストに二重に添付することを避けるのにも役立ちます。

パフォーマンス上の理由からこの方法を絶対に使用する必要がない限り、この方法は危険な地面を踏んでいるように見えると思います。私の意見では、最初にデータベースからエンティティを取得し、プロパティを手動で更新して保存する方がはるかに優れています。これにより、長期的には頭痛が軽減される可能性があります。

于 2012-05-06T05:57:06.217 に答える