简体   繁体   English

实体框架DbContext实例DataReader已打开

[英]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. 我没有太多有关Entity Framework的经验,所以我将尽力提供尽可能多的信息,并尽量不要使它太长。

This is my DbContext: 这是我的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. 已经有一个与此连接相关联的打开的DataReader,必须先关闭它。

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. 我读过有关MultipleActiveResultSets的信息,但我正在使用MySQL,似乎不支持它。

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. 最好为每个线程/请求创建一个新的DBContext实例。 Sharing same DbContext by threads is dangerous and objectionable. 通过线程共享相同的DbContext是危险且令人反感的。 It will be cause that different thread try to use same DBContext instance which it is being already used. 这将导致不同的线程尝试使用已被使用的相同DBContext实例。

Also, there is a very good article here about the UnitOfWork, Transaction Management and benefits of creating the DbContext for per thread/request. 另外,这里有一篇很好的文章关于UnitOfWork,事务管理以及为每个线程/请求创建DbContext的好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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