【问题标题】:Entity Framework DbContext Instance DataReader already open实体框架 DbContext 实例 DataReader 已打开
【发布时间】:2018-05-30 04:51:30
【问题描述】:

我对 Entity Framework 没有太多经验,所以我会尽量提供尽可能多的信息,并且尽量不要让这篇文章太长。

这是我的 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());
        }
    }
}

因此,它为我访问的所有连接使用一个实例,如下所示:

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

而且运行良好!

虽然,偶尔我会收到此错误:

已经有一个打开的 DataReader 与此 Connection 关联,必须先关闭它。

我想这是因为它试图使用已经在使用的实例。

我一直在寻找如何修复它的几天,但我仍然无法让它工作。我已经阅读了 MultipleActiveResultSets,但我使用的是 MySQL,但它似乎不受支持。

【问题讨论】:

  • 绝不对实体框架 DbContext 使用单例。不仅 Singleton 是一种反模式,而且它是 EF 所能做的最糟糕的事情。
  • 我想,这样做可以吗? using (var ctx = new ContextFactory().Create()) { // crud }}

标签: c# mysql entity-framework


【解决方案1】:

你应该改变它

private static DefaultDbContext _instance;

[ThreadStatic]
private static DefaultDbContext _instance;

最好为每个线程/请求创建一个新的DBContext 实例。通过线程共享相同的DbContext 是危险且令人反感的。这将导致不同的线程尝试使用相同的 DBContext 实例,它已经被使用了。

此外,还有一篇非常好的文章 here,关于 UnitOfWork、事务管理以及为每个线程/请求创建 DbContext 的好处。

【讨论】:

  • 谢谢!是啊,你说得对。我应该重构它并为每个请求创建一个新的,但现在就可以了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 2011-06-19
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
  • 2013-12-26
  • 2022-12-12
相关资源
最近更新 更多