0

Perplexed by an occurrence of the common Entity Framework error

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

My understanding of this error is that it meant there was another object somewhere in the graph of that object type which had a duplicate primary key, preventing a second copy being attached.

But that understanding must be wrong, because the error is occurring here:

public void Update(MyType updateItem)
{
    if (updateItem != null)
    {
        // debug code, which tells me there is only one match
        var foo = Entities.MyTypes.Where(x => x.MyTypeId == updateItem.MyTypeId);

        if (Entities.MyTypes.Any(itm => itm.MyTypeId == updateItem.MyTypeId))
        {
            // error here
            Entities.Entry(updateItem).State = System.Data.Entity.EntityState.Modified;
        }
        else
        {
            Entities.MyTypes.Add(updateItem);
        }
    }
}

So that's not trying to add, or re-attach a new object, it's just saying that an existing object is marked as modified, right?

Can someone please explain to me the process here, so I can try and understand and fix the problem?

EDIT: This is the SQL it's trying to run

exec sp_executesql N'SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [dbo].[MyType] AS [Extent1]
    WHERE [Extent1].[MyTypeId] = @p__linq__0
)) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]',N'@p__linq__0 int',@p__linq__0=4749

Which returns a C1 value of 1. The next entry in the trace is the logger logging the error.

Bob Tway
  • 9,301
  • 17
  • 80
  • 162
  • What's the primary key of `updateItem`? Are you using sql server? – Kosala W Mar 10 '16 at 10:36
  • @KosalaW It's SQL Server. The primary key is a standard, auto-incrementing int indentity (1,1) Id field. – Bob Tway Mar 10 '16 at 10:39
  • 1
    The error is coming from your database. By looking at the above code, we can't say what's happening. To diagnose this issue, you have to use `sql server profiler`. Start the profiler, run your system and capture the sql that throws this primary key violation exception. Then you should be able to figure out why it's trying to insert/update identity value. – Kosala W Mar 10 '16 at 10:44
  • If you are using edmx, make sure your model is updated with latest database changes. – Kosala W Mar 10 '16 at 10:45
  • 1
    I had the same problem, but if You would look at this article Craig comment you can solve it, but in other way... http://stackoverflow.com/questions/25894587/how-to-update-record-using-entity-framework-6 –  Mar 10 '16 at 10:47
  • @KosalaW OK, I've got a planning meeting now but will check the profile when I get out. I was under the impression that EF normally gave you actual Db level errors in the InnerException, but there's nothing like that here. – Bob Tway Mar 10 '16 at 10:50
  • That's a valid point. It's hard to diagnose db level issues by looking at EF exceptions. As DntQuitPls mentioned, it's better to change your syntax to less confusing _load and update_ syntax. Also Change your method name to `AddUpdate` if you are planing to perform both add and update in the same function. – Kosala W Mar 10 '16 at 11:01
  • @KosalaW As I suspected, there's no SQL error. I've updated the question with the sql that it's running, which seems to be fine. – Bob Tway Mar 10 '16 at 12:22
  • You might have a look at my answer on [ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value](http://stackoverflow.com/questions/23201907/asp-net-mvc-attaching-an-entity-of-type-modelname-failed-because-another-ent/39557606#39557606). – Murat Yıldız Sep 18 '16 at 12:36

1 Answers1

0

After many wasted hours, I discovered that this works, as per this answer: https://stackoverflow.com/a/31771363/271907

// needs this namespace
using System.Data.Entity.Migrations;

public void Update(MyType updateItem)
{
    if (updateItem != null)
    {
        if (Entities.MyTypes.Any(itm => itm.MyTypeId == updateItem.MyTypeId))
        {
            try
            {
                Entities.Entry(updateItem).State = System.Data.Entity.EntityState.Modified;
            }
            catch
            {
                Entities.Set<MyType>().AddOrUpdate(updateItem);
            }
        }
        else
        {
            Entities.MyTypes.Add(updateItem);
        }
    }
}

However, I must confess I do not understand why it works at all and I remain bemused by the cause of the original error.

I likely don't need the try/catch block in there - perhaps I should just swap out the State = Modified for the call to AddOrUpdate(). But because the old code was functional, and I'm not sure why this works, I felt it wisest to leave it alone.

Community
  • 1
  • 1
Bob Tway
  • 9,301
  • 17
  • 80
  • 162