简体   繁体   中英

Entity Framework DbContext Instance DataReader already open

I don't have much experience with Entity Framework, so I'll try to give as much information I can and try not to make this too long.

This is my DbContext:

using MySql.Data.Entity;
using MySql.Data.MySqlClient;
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations;

namespace src.Database.Models
{
    [DbConfigurationType(typeof(MySqlEFConfiguration))]
    public class DefaultDbContext : DbContext
    {
        public DefaultDbContext(string connectionString) : base(connectionString)
        {
            System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultDbContext, MigrationConfiguration>());
        }

        public DbSet<User> Users { get; set; }
        public DbSet<Character> Characters { get; set; }
        public DbSet<CharacterClothes> CharacterClothes { get; set; }
        public DbSet<CharacterVehicles> CharacterVehicles { get; set; }
        public DbSet<Dealership> Dealership { get; set; }
        public DbSet<DealershipVehicle> DealershipVehicles { get; set; }
    }

    public class ContextFactory : IDbContextFactory<DefaultDbContext>
    {
        private static string ConnectionString;

        public static void SetConnectionParameters(string serverAddress, string username, string password, string database, uint port = 3306)
        {
            var connectionStringBuilder = new MySqlConnectionStringBuilder()
            {
                Server = serverAddress,
                UserID = username,
                Password = password,
                Database = database,
                Port = port
            };

            ConnectionString = connectionStringBuilder.ToString();
        }

        private static DefaultDbContext _instance;

        public static DefaultDbContext Instance
        {
            get
            {
                if (_instance != null) return _instance;
                return _instance = new ContextFactory().Create();
            }
            private set { }
        }

        public DefaultDbContext Create()
        {
            if (string.IsNullOrEmpty(ConnectionString)) throw new InvalidOperationException("Please set the connection parameters before trying to instantiate a database connection.");

            return new DefaultDbContext(ConnectionString);
        }
    }

    internal sealed class MigrationConfiguration : DbMigrationsConfiguration<DefaultDbContext>
    {
        public MigrationConfiguration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
            SetSqlGenerator("MySql.Data.MySqlClient", new MySqlMigrationSqlGenerator());
        }
    }
}

So, it is using an instance for all connections which i access like this:

var user = ContextFactory.Instance.Users.FirstOrDefault(x => x.id == id);
var dealerships = ContextFactory.Instance.Dealership.ToList();

And it is working fine!

Though, occasionally I get this error:

There is already an open DataReader associated with this Connection which must be closed first.

Which I suppose it's because it's trying to use the Instance while it's already in use.

I've been searching for days on how to fix it, but still i couldn't make it work. I've read about MultipleActiveResultSets but i'm using MySQL and it seems it isn't supported.

You should change it

private static DefaultDbContext _instance;

to

[ThreadStatic]
private static DefaultDbContext _instance;

It could be better to create a new DBContext instance for per thread/request. Sharing same DbContext by threads is dangerous and objectionable. It will be cause that different thread try to use same DBContext instance which it is being already used.

Also, there is a very good article here about the UnitOfWork, Transaction Management and benefits of creating the DbContext for per thread/request.

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