简体   繁体   中英

Update specific fields in Entity Framework

I have a model:

public class VR
{
    [Key]
    public int ID { get; set; }
    public string FullName { get; set; }
    public string CreatedBy { get; set; }
    public DateTime? Created { get; set; }
    public string ModifiedBy { get; set; }
    public DateTime? Modified { get; set; }
}

My controller's Edit function:

    // POST: VRs/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Edit(VR vR)
    {
        if (ModelState.IsValid)
        {
            var Result = (from c in _context.MyVR.Where(c => c.ID == vR.ID) select c).Single();

            vR.Created = Result.Created;
            vR.CreatedBy = Result.CreatedBy;
            vR.ModifiedBy = User.Identity.Name;
            vR.Modified = DateTime.Now;
        
            _context.Update(vR);
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(vR);
    }

and I get the error below:

The instance of entity type ' UNTest.ViewModels.VR ' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values.

You can Attach the entity to avoid loading it from DB (save performance) and update only the fields you want.

This also avoids the problem of your code when you load an instance from the DB ( Result ) and track another instance with the same Id ( vR ) resulting in an exception.

// POST: VRs/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Edit(VR vR)
    {
        if (ModelState.IsValid)
        {
            //Attach the instance so that we don't need to load it from the DB
            _context.MyVR.Attach(vR);

            vR.ModifiedBy = User.Identity.Name;
            vR.Modified = DateTime.Now;

            //Specify the fields that should be updated.
            _context.Entry(vR).Property(x => x.ModifiedBy).IsModified = true;
            _context.Entry(vR).Property(x => x.Modified).IsModified = true;

            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(vR);
    }

The other way to specify fields that should not be updated.

// POST: VRs/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Edit(VR vR)
        {
            if (ModelState.IsValid)
            {
                //Attach the instance so that we don't need to load it from the DB
                _context.Entry(vR).State = EntityState.Modified; 

                vR.ModifiedBy = User.Identity.Name;
                vR.Modified = DateTime.Now;

                //Specify the fields that should not be updated.
                _context.Entry(vR).Property(x => x.Created).IsModified = false;
                _context.Entry(vR).Property(x => x.CreatedBy).IsModified = false;

                _context.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(vR);
        }

In case you use a view model, you can use new operator to create your data model and copy the fields you want to update:

// POST: VRs/Edit/5
            [HttpPost]
            [ValidateAntiForgeryToken]
            public IActionResult Edit(VRViewModel vRVM)
            {
                if (ModelState.IsValid)
                {
                    VR vR = new VR();
                    //Attach the instance so that we don't need to load it from the DB
                    _context.MyVR.Attach(vR);

                    //Set the Id for your model.
                    vR.Id = vRVM.Id;
                    //Let's say you also want to update this field from the VM
                    vR.FullName = vRVM.FullName;

                    vR.ModifiedBy = User.Identity.Name;
                    vR.Modified = DateTime.Now;

                    //Specify the fields that should be updated.
                    _context.Entry(vR).Property(x => x.ModifiedBy).IsModified = true;
                    _context.Entry(vR).Property(x => x.Modified).IsModified = true;
                    _context.Entry(vR).Property(x => x.FullName).IsModified = true;

                    _context.SaveChanges();
                    return RedirectToAction("Index");
                }
                //create your new view model and return it. For demonstration purpose, I return the same view model, in your real code, you can adjust it.
                return View(vRVM);
            }

You have retrieved the data entity from the context so its being tracked. You cannot then track another entity with the same ID in the same context.

Change the POST method to update the data model from the view model, and save the data model

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VR vR)
{
    if (ModelState.IsValid)
    {
        var result = (from c in _context.MyVR.Where(c => c.ID == vR.ID) select c)
           .FirstOrDefault(); // use FirstOrDefault() to prevent an exception if the user changes you input for the ID.
        if (result != null)
        {
           result.FullName = vR.FullName;
           result.ModifiedBy = User.Identity.Name;
           result.Modified = DateTime.Now;
           _context.Update(result);
           _context.SaveChanges();
            return RedirectToAction("Index");
        }
    return View(vR);
}

I am late to the party, but. Copied below code from above answer.

// POST: VRs/Edit/5.

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VR vR)
{
    if (ModelState.IsValid)
    {
        //Attach the instance so that we don't need to load it from the DB
        _context.MyVR.Attach(vR);

        //vR.ModifiedBy = User.Identity.Name;
        //vR.Modified = DateTime.Now;
        _context.MyVR.Attach(vR).State = EntityState.Modified;
        //Specify the fields that should be updated.
        _context.Entry(vR).Property(x => x.ModifiedBy).IsModified = true;
        _context.Entry(vR).Property(x => x.Modified).IsModified = true;

        _context.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(vR);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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