Asp.Net MVC - Attaching an Entity of Type 'Modelname' Failed Because Another Entity of the Same Type Already Has the Same Primary Key Value

ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value

Problem SOLVED!

Attach method could potentially help somebody but it wouldn't help in this situation as the document was already being tracked while being loaded in Edit GET controller function. Attach would throw exactly the same error.

The issue I encounter here was caused by function canUserAccessA() which loads the A entity before updating the state of object a. This was screwing up the tracked entity and it was changing state of a object to Detached.

The solution was to amend canUserAccessA() so that the object I was loading wouldn't be tracked. Function AsNoTracking() should be called while querying the context.

// User -> Receipt validation
private bool canUserAccessA(int aID)
{
int userID = WebSecurity.GetUserId(User.Identity.Name);
int aFound = db.Model.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();

return (aFound > 0); //if aFound > 0, then return true, else return false.
}

For some reason I couldnt use .Find(aID) with AsNoTracking() but it doesn't really matter as I could achieve the same by changing the query.

Hope this will help anybody with similar problem!

Failed because another entity of the same type already has the same primary key value As

The problem was solved this way.

public bool Edit(WorkshopReport updated)
{
try
{
var local = _ctx.Set<WorkshopReport>()
.Local
.FirstOrDefault(f => f.Id == updated.Id);
if (local != null)
{
_ctx.Entry(local).State = EntityState.Detached;
}
_ctx.Entry(updated).State = System.Data.Entity.EntityState.Modified;
return true;
}
catch (Exception ex)
{
// TODO log this error
return false;
}
}

Attaching an entity of type 'X' failed because another entity of the same type already has the same primary key value. error

The first three solutions did not work. What I was ultimately forced to do to get a solution was follow along with your side note (at least I think that is what you were getting at). The issue was arising because the includes of the GameType and AppplicationUsers' were trying to create new entities of their respective objects instead of finding the information in the database and setting it to modified. Below is the updated controller code that has gotten it working:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(EditMatchesViewModel match)
{

if (ModelState.IsValid)
{
var updatedMatch = db.Matches.Find(match.ID);
updatedMatch.Date = match.Date;
updatedMatch.AwayTeam = match.AwayTeam;
updatedMatch.HomeTeam = match.HomeTeam;
updatedMatch.Division = match.Division;
updatedMatch.Games = new List<Game>();

foreach (var game in match.Games)
{
if (game.ID > 0)
{
var updatedGame = db.Games.Find(game.ID);
updatedGame.GameType = db.GameType.Find(game.GameType.ID);
updatedGame.AwayPlayer1 = db.Users.Find(game.AwayPlayer1.Id);
updatedGame.AwayPlayer2 = db.Users.Find(game.AwayPlayer2.Id);
updatedGame.HomePlayer1 = db.Users.Find(game.HomePlayer1.Id);
updatedGame.HomePlayer2 = db.Users.Find(game.HomePlayer2.Id);
updatedGame.AwayScore1 = game.AwayScore1;
updatedGame.AwayScore2 = game.AwayScore2;
updatedGame.HomeScore1 = game.HomeScore1;
updatedGame.HomeScore2 = game.HomeScore2;

updatedMatch.Games.Add(updatedGame);
}
}
db.Matches.Attach(updatedMatch);
db.Entry(updatedMatch).State = EntityState.Modified;
await db.SaveChangesAsync();

return RedirectToAction("Index");
}
return View(match);
}

Attaching an entity of type failed because another entity of the same type already has the same primary key value

It's hard to be sure as the code you've shared appears to be a wrapper built around Entity Framework and so obscures away some of the necessary detail but an educated guess says that you're dealing with Detached Entities.

The keyword to search for is DbContext (Database Context).

If you use Entity Framework (EF) to fetch some data from your database this data remains attached to the database or DbContext, this is an attached entity.

Any changes made to the data are now automatically tracked by EF so when you call SaveChanges() it knows to UPDATE the existing data.

In your case I suspect that _jobQueueUnitOfWork.JobQueueRepository.GetAll(); fetches data from somewhere else such as a Web API. As this data was created outside of DbContext then EF can't possibly know what state it's in, this is a detached entity.

The solution is to simply tell EF what state the data is in, in your case it's modified and requires an UPDATE over an INSERT.

tempList.ForEach(jq => 
{
context.jobqueue.Attach(jq); // Attach to `DbContext`
context.Entry(jq).State = System.Data.Entity.EntityState.Modified; // Modified
});

If you search for Entity Framework articles relating to dbcontext, change tracking and attached/detached entities it should answer a lot of your questions.

Attaching an entity of type '' failed because another entity has the same primary key value

This is the code that is causing the problem:

  var dbEntity = await _context.Set<T>().SingleOrDefaultAsync(x => x.Id == entity.Id);
_context.Set<T>().Attach(entity);

In this scenario, if you find an existing entity, it just got stored in the context. If you try to add one that already exists, EF can't handle that. There are a couple of ways you can get around this. I'll show two:

 var dbEntity = await _context.Set<T>().AsNoTracking().SingleOrDefaultAsync(x => x.Id == entity.Id);

In theory, if you don't track it, then you should be able to add the other one.

However, I think this way is better:

bool doesEntityExist = await _context.Set<T>().Any(x => x.Id == entity.Id);
_context.Set<T>().Attach(entity);
_context.Entry(entity).State = doesEntityExist ? EntityState.Modified : EntityState.Added;

Attaching an entity of type 'ModelName failed because another entity of the same type already has the same primary key value

Entity Framework tracks objects you have loaded. So when you query the database for the OldConnector object, that item is kept in memory.

You then go on to try and save your NewConnector object which has the same primary key ID. Entity Framework checks it's internal state and finds a matching entity, that is why you get the error. Since you are trying to update the existing object, you should do this instead:

public void Update(Connector newConnector)
{
if (newConnector == null)
{
throw new ArgumentNullException(nameof(newConnector));
}

var oldConnector = _db.ConnectorsTable
.Where(x => x.ID == newConnector.ID)
.Single(); //Grabbing the old connectors password

if (newConnector.Password == "")
{
newConnector.Password = oldConnector.Password;
}

//Update the old entity with values from the new entity:
_db.Entry(oldConnector).CurrentValues.SetValues(newConnector);
_db.SaveChanges();
}


Related Topics



Leave a reply



Submit