Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error attaching entity because of same primary key when trying to save an update

I am trying to save an update to an existing database entry but when I do I get the error:

Attaching an entity of type 'FFInfo.DAL.Location' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

This is my controller's code. The save method I am using is the same I use in a few other areas to update data with no problems.

[HttpPost, ValidateAntiForgeryToken]
public ActionResult EditLocation(AddEditLocationVM model, HttpPostedFileBase MapFile)
{
    try
    {
        using (var db = new GeographyContext())
        {
            model.Sections = new SelectList(db.Sections.Where(s => s.ID > 1).OrderBy(s => s.Title), "ID", "Title").ToList();
            model.GeographyTypes = new SelectList(db.GeographyTypes.Where(gt => gt.SectionID == model.Section).OrderBy(gt => gt.Name), "ID", "Name").ToList();
            model.ParentLocations = new SelectList(db.Locations.Where(l => l.SectionID == model.Section).OrderBy(l => l.Name), "ID", "Name").ToList();


            if (MapFile != null)
            {
                if (FileHelper.IsNotValidImage(MapFile))
                {
                    ModelState.AddModelError("Invaalid File Type", "Images must be JPG, GIF, or PNG files.");
                }
            }

            if (ModelState.IsValid)
            {
                if (MapFile != null)
                {
                    var SectionRoute = db.Sections.Where(s => s.ID == model.Section).Select(s => s.Route).First();
                    model.MapFileID = FileHelper.UploadFile("Images/" + SectionRoute + "/Maps/" + MapFile.FileName.ToList(), "site", MapFile);
                }

                if (model.ParentLocation == 0)
                {
                    model.ParentLocation = null;
                }

                var UpdatedLocation = new Location()
                {
                    Description = model.Description,
                    GeographyTypeID = model.GeographyType,
                    ID = model.ID,
                    MapFileID = model.MapFileID,
                    Name = model.Name,
                    ParentLocationID = model.ParentLocation,
                    SectionID = model.Section
                };

                db.Entry(UpdatedLocation).State = EntityState.Modified;
                db.SaveChanges();
                ViewBag.Results = "Location information updated.";
            }

            return View(model);
        }
    }
    catch (Exception ex)
    {
        ErrorSignal.FromCurrentContext().Raise(ex);
        model.Sections = Enumerable.Empty<SelectListItem>();
        ViewBag.Results = "Error updating location informaiton, please try again later.";
        return View(model);
    }
}

This is my Location Entity code:

public class Location
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    [Required, Index("IX_Location", 1, IsUnique = true)]
    public string Name { get; set; }

    [Index("IX_Location", 2, IsUnique = true)]
    public Int16 SectionID { get; set; }

    [Column(TypeName = "varchar(MAX)")]
    public string Description { get; set; }

    public Int16 GeographyTypeID { get; set; }
    public int? MapFileID { get; set; }
    public int? ParentLocationID { get; set; }

    [ForeignKey("SectionID")]
    public Section Section { get; set; }

    [ForeignKey("GeographyTypeID")]
    public GeographyType GeographyType { get; set; }

    [ForeignKey("MapFileID")]
    public File Map { get; set; }

    [ForeignKey("ParentLocationID")]
    public Location ParentLocation { get; set; }

    public ICollection<LocationTransitionPoint> TransitionPoints { get; set; }
}

This is my first time trying to update a more complex entity like this but from what I have found on the web I can not see anything wrong.

like image 475
Matthew Verstraete Avatar asked Sep 12 '15 16:09

Matthew Verstraete


People also ask

Can you update a primary key in Entity Framework?

You cannot update the primary key through entity framework, since entity framework would not know which database row to update. However, if you really need to do it, you could write a stored procedure that updates the primary key, and then execute the stored procedure from entity framework.

How do you update an entity?

How to Update a new record in to a existing entity using update entity action? First you need to check the id if id exist then you can use the update entity action and if id is new then you can used the create entity action.

How do you attach entity to context?

Add() method attaches the entire entity graph to a context and automatically applies the Added state to all entities. The DbSet. Add() method attaches the entire entity graph to a context with the Added state to each entity. Calling context.


1 Answers

You can not have two entities (same type) with same primary keys in memory in Entity Framework.

The problem is

model.ParentLocations = new SelectList(db.Locations.Where(l => l.SectionID == model.Section).OrderBy(l => l.Name), "ID", "Name").ToList();

in above line you somehow have loaded the Location which its ID is model.ID

then in

var UpdatedLocation = new Location()
{
    Description = model.Description,
    GeographyTypeID = model.GeographyType,
    ID = model.ID,
    MapFileID = model.MapFileID,
    Name = model.Name,
    ParentLocationID = model.ParentLocation,
    SectionID = model.Section
};
db.Entry(UpdatedLocation).State = EntityState.Modified;

You are creating a new Location and trying to attach it to context (by setting it's state as modified), but you have loaded another Location entity with exact primary key as UpdatedLocation into memory somewhere and this cause the exception.

Try fetching the the location and then change the roperties.

var UpdateLocation = db.Locations.First(l => l.ID == model.ID);
// var UpdateLocation = db.Locations.Find(model.ID); maybe a better option
UpdatedLocation.Description = model.Description;
UpdatedLocation.GeographyTypeID = model.GeographyType;
UpdatedLocation.MapFileID = model.MapFileID;
UpdatedLocation.Name = model.Name;
UpdatedLocation.ParentLocationID = model.ParentLocation;
UpdatedLocation.SectionID = model.Section;
like image 53
Hamid Pourjam Avatar answered Sep 26 '22 02:09

Hamid Pourjam