In our EF 5 application, when we get a SQL Server deadlock error on an insert or update, we immediately try the operation again. However, when we attempt to do so, we're getting the following error:
"Conflicting changes detected. This may happen when trying to insert multiple entities with the same key."
This error is not coming from SQL Server. This is an EF 5 error. And we are not attempting to insert multiple entities with the same key. IOW, we're not attempting to insert a duplicate row. However, I suspect this error means something else. But I'm not entirely certain I know what the issue is. If I had to guess, I would say that on the first attempt, EF sees where trying to insert an entity. It fails because of a deadlock. When we immediately try again, EF thinks we're trying to do the very same operation again, with the same key, and doesn't like it. Not sure how to get around this.
It sounds like you might be trying to execute your queries against the same instance of the DbContext. In which case, your changes are already pending from the last try.
Since there is no “undo pending changes” on the context, you must dispose and recreate the context in between “retries”.
Related
I am chasing an issue with MySql / EF Core where I randomly have an exception thrown saying Nested transactions are not supported. This exception does not occur when my system is only used by one user. But when I run my tests in parallel or when I have multiple users, the exception occurs. I looked at all the code and their is nothing that could create nested transactions.
The only piece of codes that scares me so far is something like the following:
using (var transaction = _context.Database.BeginTransaction())
{
// Create a few entities and add them to the EF context
...
// Insert the rows: hopefully at this point, my transaction is not commited yet.
_context.SaveChanges();
// I then want to update a few rows with a raw sql statement without
// having to load the entities in memory.
_context.Database.ExecuteSqlCommand("UPDATE ...");
// Now that I have inserted and inserted some data, I want to commit all these
// changes atomically.
transaction.Commit();
}
Is this safe? Am I guaranteed that my SaveChanges and ExecuteSqlCommand will be executed on the same MySqlConnection? I have the feeling that when I call SaveChanges, it closes my connection and puts it back on the connection pool. Then, my ExecuteSqlCommand takes a new connection from the pool (it may be the same one or another one). So my initial connection (the one where I opened the transaction) is put back in the pool and it could be reused by another thread.
This is just a hunch and I am totally not sure if this could cause the problem.
My real question in the end is:
is it safe to use SaveChanges and ExecuteSqlCommand within a transaction?
I upgraded from MySql.Data.EntityFrameworkCore/MySql.Data 6.10.1-beta to 6.10.3-rc and it looks like the problem is gone. Since the problem was random I can't be totally sure that the problem is indeed fixed, but so far so good.
EDIT:
3 years later, the problem was never observed anymore.
I am encountering this situation where EF6 is used to save an object to the database (into 2 separate tables). Thus, by executing SaveChanges() in EF, this generated 2 seperate exec sp_executesql insert... statements.
This is where the value generated from the first insert will be used as an input parameter to the second statement.
One thing I noticed though is that when the second statement failed in one case, no records were written.
I pulled up SQL-Profiler and did not see any rollbacks being made either; can't seem to figure out how this rollback actually occurred.
Appreciate any advice pls.
One thing I noticed though is that when the second statement failed in one case, no records were written.
I pulled up SQL-Profiler and did not see any rollbacks being made either; can't seem to figure out how this rollback actually occurred.
By calling SaveChanges() on your EF context, all modifications made to your entities (insert, update, delete etc) are wrapping into a single SQL transaction. This is a default behavior in EF.
The purpose of a transaction is to take all the SQL statements as a single operation, a unit of work. If one statement fails at the middle or at the end then all passed statements are rollback even those that are executed successfully.
To prevent this you can call SaveChanges() separately for each changes you made in your EF context.
I have a trigger in DB that forbids inserting duplicated data. When I enter duplicated data, it adds nothing to the table, OptimisticConcurrencyException is thrown and I am swallowing (ignoring) this exception. When I try to enter new correct object, EF tries to run both INSERTs and it fails again on the first one.
How can I recover from this, all examples are discussing failed UPDATES, is there anything about INSERT? As I have read creating new DatabaseContext will solve the problem, but I cannot do it that way.
Creating a new DatabaseContext is always the best choice (since Hibernate).
In your case you need to remove the entity that caused the error from the context.
((IObjectContextAdapter)context).ObjectContext.Detach(entity);
You can ask ObjectContext to ignore all the changes after the ignorable exception is thrown. This way the added entity is marked Unchanged; hence in the next SaveChanges call, context won't consider it to manipulate DB:
(yourContextObject as IObjectContextAdapter).AcceptAllChanges();
I'm using Entity Framework 4.1 and have a seemingly simple requirement: I want to either get an entity by a unique key, or if it doesn't already exist, create it:
var user = db.Users.SingleOrDefault(u => u.Sid == sid);
if (user != null)
return user;
user = new User(sid);
db.Users.Add(user);
Normally this works fine, but when I run a bunch of tests together (using MSTest) one of them consistently fails with "Sequence contains more than one element". When I run that test by itself it works fine.
The problem seems obvious: multiple threads are calling the above code concurrently and each create a new User row. But what is the solution?
The proper solution is a transaction, of course, but I just cannot get it to work. EF won't use a normal DbTransaction if I start one. If I use a TransactionScope it either has no effect (the same error occurs) or EF tries and fails to start a distributed transaction, even if I follow the advice about opening a connection first.
This is really frustrating, because it is such a trivial thing to do with plain old SQL: begin transaction, SELECT, INSERT, commit transaction. How can I get this to work in EF? It doesn't have to be using transactions - whatever makes it work.
The first statement (the only one which could cause the error you describe) will never fail if your DB has a UNIQUE constraint on Sid. Does it? It should. That's the only way to make sure that the sid is truly, globally unique.
I have a windows service that runs every 10 seconds ... each time it runs, it takes some test data, modifies it and persists it to the database using the EntityFramework. However, on every second run, when I try to persist the change I get the following Optimistic Concurrency Exception:-
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries
I know for a fact that there is nothing else writing to that DB but my service which updates records every 10 seconds. What could be causing the concurrency exception here ?
I think a related entity somewhere in the object graph was getting modified prior to the second save operation.
All i am doing really is instantiating a new object context, and calling a save operation on some records i had retrieved using the same context.
The following code worked ---
var ctx = new blahEntities();
var profile = ctx.ProfileSet.Where(pr=>pr.FirstName.Contains("a")).FirstOrDefault();
profile.Address = "modified";
ctx.SaveChanges();
ctx.Refresh(RefreshMode.StoreWins,profile);
The "unexpected number of rows (0)" indicates that more than likely you don't have an ID field correctly mapped or defined in your entity model, or you are modifying a detached entity and attempting to save it and it doesn't have key information.
Run SQL Server profiler, or Entity Framework Profiler, and see what is going on in the background.
Once had this same issue and spent hours tracking it down to a malfunctioning update trigger. If you have any triggers on the table that's being updated, make sure they're working correctly. I work in an Oracle environment, fwiw.