1

I have a problem when adding posts to my DB, this "Add" function is called from multiple threads. And usually very quick after eachother, I dont know if this matters, but thats the way it works.

Code:

private object dbLock = new object();

public void Add(string fileName, DateTime collectionTime)
    {
        try
        {
            lock (dbLock)
            {
                var collection = new Collection
                {
                    Filename = fileName,
                    Datetime = collectionTime,
                };
                _entities.AddToCollection(collection);
                _entities.SaveChanges();
                CollectionChanged(collection, null);
            }
        }
        catch (Exception ex)
        {
        }
        finally
        {

        }
    }

My problem is that when SaveChanges is called I get this exception:

The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

All answers I managed to find has something to do with that you have to add StoreGeneratedPattern="Identity", I allready did this, but it doesn't help

<Property Name="ID" Type="integer" Nullable="false" StoreGeneratedPattern="Identity" />

So is there any other way to solve this?

2
  • "Inconsistent" always indicates that a process has not yet completely terminated ist work. If you are accessing your DB with multiple threads, either the DBMS must be able to handle this or your code must be made thread-safe Commented Jun 18, 2013 at 8:31
  • using an object-context from multiple threads usually means something very bad is happening - that is not the expected usage, and can lead to very bad things. Swallowing the exception is a really bad idea, too. Can you expand on what the scenario here is? what sort of application is this, and why is it sharing an object-context between threads? Commented Jun 18, 2013 at 8:31

1 Answer 1

3

Ultimately, sharing an object-context between threads is a really really bad idea. An object-context is intended to be used as a unit of work - i.e. short-lived; typical usage:

using(var ctx = new SomeObjectContextType()) // assuming IDisposable
{
    // not shown: get some records, if needed
    ...
    // not shown: update, add, remove some records, if needed

    ctx.SaveChanges();
} // and now it is gone, never to be used again

It might get a bit more complex than that in some scenarios, for example keeping an object-context for the duration of a page / request, but it should not be shared between callers. The reasons for this are many, but fundamentally all competing updates would need to be locked, and "updates" here includes the simple act of reading any record from a database, or lazily loading a property. It should not be surprising that an object-context gets temperamental when accessed by multiple threads: that scenario is not (usually) supported.

Additionally, there are other issues with having a long-lived object context:

  • occasionally, things go bad (for example a timeout, deadlock, rollback, or just a simple connection error); here the appropriate way to respond is simply to discard your now broken object context (Dispose() it if appropriate) - and forget about it; if you want to reapply your change, you start from a fresh object-context
  • the object-context includes an identity map and change management systems; if you keep it for longer than a single operation, you are slowly accumulating more and more objects into it; in addition to causing memory issues, this gradually degrades performance - as every single read / update operation now has ever-increasing amounts of data to trawl through

Basically, the "fix" here is: don't do that. That isn't the correct usage of an object-context. Do not have an application-wide shared object context.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! This looks to be working, If i do like this, could I even skip my lock then?
@Nick3 yes; if there is no shared object-contexts, there is no reason to synchronize

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.