简体   繁体   中英

Concurrency issues with EF5 / Base Repository

I've finished writing a new application which has now been deployed into the live environment however my global error handler is picking up these exceptions several times throughout the day. These errors come in batches and are one of the four in bold.

MVC 4, IIS 6, Windows Server 2003, .Net .4.0, EF 5 (latest from NuGet)

The type 'ARandomModelInMyContext' has been mapped more than once.

Index was out of range. Must be non-negative and less than the size of the collection.

Parameter name: index
System.ThrowHelper.ThrowArgumentOutOfRangeException() at System.Data.Metadata.Edm.MetadataCollection`1.get_Item(Int32 index) at System.Data.Mapping.DefaultObjectMappingItemCollection.ContainsMap(GlobalItem cspaceItem, ObjectTypeMapping& map) at

The context cannot be used while the model is being created.

System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()

The underlying provider failed on Open. The connection was not closed. The connection's current state is connecting.

The structure of the application is a pretty standard MVC4 application with a Service Layer and a repository layer.

  • A service creates a repo in the constructor
  • Repository creates a new Context in the repository constructor like so:

public class MyRepository : BaseRepository<MyModel>, IMyRepository

With the constructor:

public MyRepository() : base(new MyEntities())
{
}

Base Repository looks like this:

public class BaseRepository<TEntity> where TEntity : class
{
    internal CRMEntities Context;
    internal DbSet<TEntity> dbSet;
    public BaseRepository(MyEntities context)
    {
        this.Context = context;
        dbSet = context.Set<TEntity>();
    }
}

There shouldn't be any concurrency issues as I'm not making directly using any threading or async.

Any ideas? Can my repository structure be improved? I've made all the constructors DI-able however I'm not using an IoC container yet.

Would wrapping the construction of the Context in the repository in lock be worth while? For example:

public class BaseRepository<TEntity> where TEntity : class
{
    internal MyEntities Context;
    internal DbSet<TEntity> dbSet;
    private static object _lock = new object();

    public BaseRepository(MyEntities context)
    {
        lock (_lock)
        {
            this.Context = context;
            dbSet = context.Set<TEntity>();
        }
    }
 }

It looks very much like your Repository (and hence your context) is used by multiple requests. if this is true, then this is multi-threaded use of the same context instance, which is not supported--the context is not thread-safe. Locking just the initialization is not sufficient. (Also, calling Set does not initialize the context.) You would need to protect all access to the context, or more appropriately use a context per request model with short-lived context instances.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM