【问题标题】:How to partly update a database record?如何部分更新数据库记录?
【发布时间】:2017-02-10 14:49:22
【问题描述】:

我正在努力实现一个简单的“更新个人资料”功能(学习目的)。我只是希望每次更新给定配置文件时都不能更新配置文件图像。当图片在那里并且配置文件的其他部分更新时,我希望图片保持不变。

为此我想出了以下代码:

控制器:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "UserDetailsId,ImageData,FirstName,LastName,UserAddress,UserCountry,UserPostalCode,UserPhoneNumber,CompanyId,identtyUserId")] UserDetails userDetails, HttpPostedFileBase UploadImage)
    {
        if (ModelState.IsValid)
        {
            if (UploadImage!=null) {
                byte[] buf = new byte[UploadImage.ContentLength];
                UploadImage.InputStream.Read(buf, 0, buf.Length);
                userDetails.ImageData = buf;
            }
            else {
                var userFromDb = db.UsersDetails.Where(u => u.identtyUserId == userDetails.identtyUserId).First();//i am getting the old user data
                userDetails.ImageData = userFromDb.ImageData; //saving the image to the modified state
            }
            db.Entry(userDetails).State = EntityState.Modified;//error here
            db.SaveChanges();
            return RedirectToAction("Index");

        }
        //ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "CompanyName", userDetails.CompanyId);
        return View(userDetails);

我在这一行遇到的错误db.Entry(userDetails).State = EntityState.Modified; 如下:

附加类型为“eksp.Models.UserDetails”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后将非新实体的状态设置为“未更改”或“已修改”。

型号:

public class UserDetails
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserDetailsId { get; set; }
    public byte[] ImageData { get; set; }
    [NotMapped]
    public HttpPostedFileBase UploadImage { get; set; }
    [NotMapped]
    public string ImageBase64 => System.Convert.ToBase64String(ImageData);
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UserPhoneNumber { get; set; }
    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }
    public string identtyUserId { get; set; }
    public virtual ICollection<WorkRolesUsersDetails> WorkRolesUsersDetails { get; set; }

虽然这对我来说可能看起来很不言自明,但不清楚这是否正在发生?

有人可以指导我如何实现我想要实现的目标吗?

谢谢!

【问题讨论】:

  • 我不确定这是否是一个理想的解决方案,但是您是否考虑过先获取记录,然后对其进行修改然后将其发回?服务器可能足够聪明,不会修改未更改的字段。
  • @JamesHughes 可以演示吗?
  • @RobertRoss,恐怕目前还没有,如果您没有得到接受的答案,我今晚会为您提供一些演示代码
  • @JamesHughes 好的,谢谢!

标签: c# asp.net-mvc entity-framework linq


【解决方案1】:

当您更新一个实体时,您应该将发布的值映射到一个从数据库中提取的实例,而不是尝试直接保存从发布数据创建的实例。这是避免使用Bind 的另一个原因,因为它会混淆问题并使不了解的开发人员更好地认为可以直接保存从帖子数据创建的实体。不是,也从来不是。

改为使用 UserDetailsId 之类的东西来查找实体:

var userDetails = db.UserDetails.Find(model.UserDetailsId);

其中model 是您操作的参数。然后,您可以将发布的值映射到您的实体:

userDetails.FirstName = model.FirstName;
// etc.

最后,保存usersDetails,它现在是来自数据库的版本,所有实体上的原始数据,在适当的地方修改为发布的数据。

现在,鉴于您需要对发布的数据进行此映射无论如何,更进一步可以创建一个视图模型,其中仅包含您需要允许用户修改的属性。然后您可以发布到that,而不是使用Bind。真的,Bind 太糟糕了。这是微软匆忙添加的东西之一,因为他们认为它解决了一个问题,但实际上最终导致了另外十个问题。

【讨论】:

  • 谢谢你的回答,我会试试这个。似乎是更好的解决方案。
【解决方案2】:

您可以在任何情况下从数据库中检索数据实体,并使用作为 Post 模型一部分的详细信息对其进行更新,并将该数据实体保存回数据库。

var userFromDb = db.UsersDetails.Where(u => u.identtyUserId == userDetails.identtyUserId).First();
if (UploadImage!=null) 
{
    byte[] buf = new byte[UploadImage.ContentLength];
    UploadImage.InputStream.Read(buf, 0, buf.Length);
    userFromDb.ImageData = buf;
}
userFromDb.FirstName = userDetails.FirstName;
userFromDb.LastName = userDetails.LastName;
userFromDb.UserAddress = userDetails.UserAddress;
userFromDb.UserCountry = userDetails.UserCountry;
userFromDb.UserPostalCode = userDetails.UserPostalCode;
userFromDb.UserPhoneNumber = userDetails.PhoneNumber;
userFromDb.CompanyId = userDetails.CompanyId;
db.SaveChanges();

这应该可以帮助您实现所需的功能。

【讨论】:

  • 在这种情况下,我只能在修改图像本身的情况下修改记录,这不是我想要的:(
  • 根据您发布的代码,只有对象的图像属性被更改?您是否正在对强制您从数据库中检索数据的对象进行其他操作?关于您的要求的更多信息将有助于提供适当的解决方案。
  • 我将模型类添加到问题中。基本上使用我发布的控制器代码,我可以更改所有属性并且它总是有效的。问题是,当我不添加图像时,它会将 null 保存到数据库中,这会破坏我的应用程序。我想要实现的是能够编辑和保存其余字段,而无需在编辑时每次上传图像。基本上我希望能够随时更新图像字段,而不是每次都更新。
  • 我更新了我的答案。我希望这能帮助您解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-26
  • 2016-01-15
  • 1970-01-01
  • 2018-06-08
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
相关资源
最近更新 更多