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

时间:2017-02-10 14:49:22

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

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

我想出了以下代码:

控制器:

[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'的实体。失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。

模特:

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; }

虽然它对我来说可能是非常自我解释,但目前尚不清楚这种情况发生了吗?

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

谢谢!

2 个答案:

答案 0 :(得分:3)

更新实体时,应将发布的值映射到从数据库中提取的实例,而不是尝试直接保存从帖子数据创建的实例。这是避免使用 private void pictureBox1_Click(object sender, EventArgs e) { WindowsMediaPlayer song = new WindowsMediaPlayer(); song.URL = "https://a.pomf.cat/my.mp3"; song.controls.play(); var wd = Screen.PrimaryScreen.WorkingArea; Random x = new Random(); Random y = new Random(); Spam firstSpamForm = new Spam(); int xnum = wd.Right - firstSpamForm.Width; int ynum = wd.Bottom - firstSpamForm.Height; firstSpamForm.Location = new Point(x.Next(xnum), y.Next(ynum)); firstSpamForm.Show(this); timer1.Start(); pictureBox1.Enabled = false; } private void timer1_Tick(object sender, EventArgs e) { var wd = Screen.PrimaryScreen.WorkingArea; timer1.Interval = 500; Random xx = new Random(); Random yy = new Random(); Random x = new Random(xx.Next(515)); Random y = new Random(yy.Next(211)); Spam namn = new Spam(); int xnum = wd.Right - namn.Width; int ynum = wd.Bottom - namn.Height; namn.Location = new Point(x.Next(xnum), y.Next(ynum)); namn.Show(this); } 的另一个原因,因为它会混淆问题并让不熟悉的开发人员认为直接保存从帖子数据创建的实体是可以的。它不是,也绝不是。

相反,请使用Bind之类的内容来查找实体:

UserDetailsId

var userDetails = db.UserDetails.Find(model.UserDetailsId); 是您的操作中的参数。然后,您可以将已发布的值映射到您的实体:

model

最后,保存userDetails.FirstName = model.FirstName; // etc. ,现在是数据库中的版本, all 实体上的原始数据,并在适当的时候修改为发布的数据。

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

答案 1 :(得分:2)

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

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

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