【问题标题】:Entity framework - View 2 Disconnected Entity update实体框架 - 查看 2 断开连接的实体更新
【发布时间】:2012-05-05 17:12:15
【问题描述】:

我有一个用户实体类:

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 编辑动作:

    [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. 我构造了空白的用户对象。
  2. 我为其分配了取自模型的 ID。
  3. 我将它附加到 DbSet 用户。
  4. 我将数据从 UserWCPModel 加载到 User 对象。
  5. 我设置了修改时间(不重要)。
  6. 我调用 db.SaveChanges()(这就是 SaveToDb 所做的)。

目标完成! 没有第二个 SELECT 查询。 不保存与模型无关的数据。 没有为每个属性调用 IsModified。 对先前输入的超出模型范围的数据没有损害。

我把它调整得太糟糕了,我不得不在这里分享它,并希望一些 cmets :D

希望有人会觉得这很有用:)

【问题讨论】:

  • 它有效,但只是因为您故意使 DB 和 UI “不一致”,可以这么说,因为您在数据库中有 optional/nullable 列但 UI 中必需的 属性。也许你想要或需要它,但我认为这是一个非常“特殊”的架构。

标签: asp.net-mvc asp.net-mvc-3 entity-framework entity-framework-4


【解决方案1】:

如果您使用这种方法更新实体,您需要非常小心;更简洁如果您尝试在同一上下文中两次更新同一实体会发生什么。 (剧透:当你尝试附加一个已经附加的实体时,你会得到一个异常)

此外,我建议您将.AsNoTracking()(请参阅my blog post on AsNoTracking)添加到所有查询中,以便在您实际执行更新之前对只读实体进行操作。这也有助于避免将实体双重附加到您的上下文中。

我想这种方法在我看来就像是在危险地带,除非出于性能原因绝对需要使用这种方法。在我看来,首先从数据库中获取实体并手动更新属性并保存它会好得多。从长远来看,这可能会让您头疼。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 2012-03-22
    相关资源
    最近更新 更多