繁体   English   中英

如何部分更新数据库记录?

[英]How to partly update a database record?

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

我想出了以下代码:

控制器:

[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;的错误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; }

尽管对我来说看起来很自我解释,但不清楚发生了什么?

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

谢谢!

更新实体时,应该将发布的值映射到从数据库拉出的实例上,而不是尝试直接保存从发布数据创建的实例。 这是避免使用Bind另一个原因,因为它使问题感到困惑,并使更不了解的开发人员认为直接保存从发布数据创建的实体是可以的。 不是,永远不会。

相反,请使用类似UserDetailsId来查找实体:

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

model是您的操作的参数。 然后,您可以将过帐的值映射到您的实体上:

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

最后,保存usersDetails (现在是数据库的版本),并在适当时将实体上的所有原始数据修改为已发布的数据。

现在,因为你需要在发布的数据要做到这一点映射反正 ,再前进一步可以创建只需要允许用户修改属性视图模型。 然后,您可以发布到该文章 ,而不是使用Bind 真的, Bind很糟糕。 这是Microsoft匆忙添加的内容之一,因为他们认为它解决了一个问题,实际上最终导致了其他十个问题。

无论如何,您都可以从数据库中检索数据实体,并使用发布模型中包含的详细信息对其进行更新,然后将该数据实体保存回数据库中。

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();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM