C# Entity Framework 6数据库优先方法中DbContext对象之间的共享连接

C# Entity Framework 6数据库优先方法中DbContext对象之间的共享连接,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我正在尝试使用EF 6在两个不同的DB上下文对象之间共享连接。 我有这里提到的代码 要为单个DB上下文工作,但一旦我尝试与另一个DB上下文对象共享连接,我就会遇到麻烦。下面是我这样做的原因 public class MyUnitOfWork { // BAD CODE : having static connection / transaction is bad design , i use DI to implement this properly withou

我正在尝试使用EF 6在两个不同的DB上下文对象之间共享连接。 我有这里提到的代码 要为单个DB上下文工作,但一旦我尝试与另一个DB上下文对象共享连接,我就会遇到麻烦。下面是我这样做的原因

public class MyUnitOfWork
{
              // BAD CODE : having static connection / transaction is bad design , i  use DI to implement  this properly without need for static fields , this code is used here to avoid having to mention my DI configuration; 
                public static EntityConnection _commonConnection ;
                public static System.Data.Entity.DbContextTransaction _commonTransaction;
                // Generic function to create DBContext object based on T supplied.
            public static T GetDbContext<T>()
            {
                 if(_commonConnection  == null)

                  {
                     // generates a generic connection string 
                        _commonConnection = new EntityConnection(DbContextBase.GenerateConnectionString()); 

                        _connection.Open();

                        _commonTransaction = _connection.BeginTransaction(System.Data.IsolationLevel.Snapshot);
                  }
                        T myContextObject = (T)Activator.CreateInstance(typeof(T), new object[1] { _connection });
                        myContextObject .Database.UseTransaction(_transaction);
                       return myContextObject;
            }
}
然后,我可以从函数中的不同位置调用GetDbContext,如下所示

GetById(int id)
{
   var dbcontext = MyUnitOfWork.GetDbContext<OrdersDbContext>();
  return dbcontext.Orders.Where(.......);


}

GetCustomerInfo( int id)
{
   var dbcontext = MyUnitOfWork.GetDbContext<CustomerDbContext>();
  return dbcontext.Customer.Where(.......);

}
GetById(int-id)
{
var dbcontext=MyUnitOfWork.GetDbContext();
返回dbcontext.Orders.Where(……);
}
GetCustomerInfo(内部id)
{
var dbcontext=MyUnitOfWork.GetDbContext();
返回dbcontext.Customer.Where(……);
}
因为我使用的是泛型元数据部分,所以实体框架中出现错误“无论名称空间如何,都不能有多个同名实体”

但是,如果我指定.csdl/.ssdl文件的名称,连接(以及事务)将不再常见,我必须为每个DBContext创建连接和事务(这是我想要避免的)

看来我遇到了麻烦。有没有一种方法可以让我使用相同的连接而不出现重复实体错误?更改实体名称以使其不同对我来说不是一个选项,因为这将是一个非常耗时的更改,我必须跨30+db上下文/EDMX文件进行更改,这将对生产产生巨大影响。

正如在使用以下代码向您的上下文提供现有事务时所见:

string GenerateConnectionString()
{
    return SharedDatabase.SQLBase.DBconnection + "multipleactiveresultsets=True;";
}


public class MyUnitOfWork
{
    SqlConnection _commonConnection;
    DbTransaction _commonTransaction;
    // Generic function to create DBContext object based on T supplied.
    public T GetDbContext<T>()
    {
        if (_commonConnection == null)
        {
            // generates a generic connection string 
            _commonConnection = new SqlConnection(DbContextBase.GenerateConnectionString());

            _commonConnection.Open();

            _commonTransaction = _connection.BeginTransaction(IsolationLevel.Snapshot);
        }

        MetadataWorkspace workspace = new MetadataWorkspace(
          string.Format("res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;", typeof(T).Name).Split('|'), 
          new Assembly[] { Assembly.GetExecutingAssembly() });

        var connection = new EntityConnection(workspace, _commonConnection);
        T myContextObject = (T)Activator.CreateInstance(typeof(T), new object[] { connection });
        myContextObject.Database.UseTransaction(_commonTransaction);
        return myContextObject;
    }
}
string GenerateConnectionString()
{
返回SharedDatabase.SQLBase.DBconnection+“multipleactiveresultsets=True;”;
}
公共类MyUnitOfWork
{
SqlConnection _commonConnection;
DbTransaction(公共事务);;
//基于提供的T创建DBContext对象的通用函数。
公共T GetDbContext()
{
if(_commonConnection==null)
{
//生成通用连接字符串
_commonConnection=新的SqlConnection(DbContextBase.GenerateConnectionString());
_commonConnection.Open();
_commonTransaction=\u connection.BeginTransaction(IsolationLevel.Snapshot);
}
MetadataWorkspace=新MetadataWorkspace(
string.Format(“res://*/{0}.csdl | res://*/{0}.ssdl | res://*/{0}.msl;”,typeof(T).Name.Split(“|”),
新程序集[]{Assembly.getExecutionGassembly()});
var连接=新的EntityConnection(工作区,_commonConnection);
T myContextObject=(T)Activator.CreateInstance(typeof(T),新对象[]{connection});
myContextObject.Database.UseTransaction(\u commonTransaction);
返回myContextObject;
}
}

为什么不将
元数据
作为GenerateConnectionString的参数?您的上下文的类型名称和相应的csdl/ssdl文件的名称是什么?@Guillaume:我可以将元数据名称作为对象。但是,连接字符串对于该上下文来说是唯一的,并且不能在另一个上下文中重用。我想要实现的是能够使用相同的连接字符串拥有多个DBContext,从而成为同一事务的一部分?他们共享同一个PorivderConnectionString。。。他们可能已经共享同一个连接池(我不是100%确定)拥有一个静态事务是一个糟糕的设计(线程安全…。@Guillaume:请注意,实际上我的事务不是静态的,它们是通过使用结构映射的临时生命周期实现的,这意味着UnitOfWork类的对象在每个http请求中只创建一次。但是,无法在这里编写和解释整个代码,因为它太长,而且与我面临的问题也不相关。不幸的是,这不起作用,它引发了一个意外的CodeFirstException。另一篇堆栈溢出文章()提到使用entityConnection来避免此错误。但使用EntityConnection会导致我在原始问题中所指的错误。@Pratik我编辑了我的答案,不确定它是否有效,但这可能会导致您找到一个有效的解决方案……抱歉,我的问题可能不够清楚,但如果我使用您提到的代码,它将出错。当GetDbContext()被调用时;函数,它将把_连接中的元数据设置为OrdersDbContext的.csdl/ssdl。当执行问题中提到的GetDbContext()部分时,_connection对象将包含OrdersDbContext的元数据,因此CutstomersDbContext无法使用。我正在寻找一种方法,使2 DBContext对象可以使用公共连接而不存在元数据问题。@Pratik在我的代码中,
\u commonConnection
是一个
SqlConnection
,并且不保留对元数据的任何引用。在保持相同的连接和事务的同时,
EntityConnection
和关联的元数据被更改。如果这不起作用,您可以尝试使用
TransactionScope
,但不建议使用EF6。您是对的,此代码确实起作用。我忽略了智能SQLConnection到EntityConnection的转换。这正是我想要的。非常感谢,你是个天才!
string GenerateConnectionString()
{
    return SharedDatabase.SQLBase.DBconnection + "multipleactiveresultsets=True;";
}


public class MyUnitOfWork
{
    SqlConnection _commonConnection;
    DbTransaction _commonTransaction;
    // Generic function to create DBContext object based on T supplied.
    public T GetDbContext<T>()
    {
        if (_commonConnection == null)
        {
            // generates a generic connection string 
            _commonConnection = new SqlConnection(DbContextBase.GenerateConnectionString());

            _commonConnection.Open();

            _commonTransaction = _connection.BeginTransaction(IsolationLevel.Snapshot);
        }

        MetadataWorkspace workspace = new MetadataWorkspace(
          string.Format("res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;", typeof(T).Name).Split('|'), 
          new Assembly[] { Assembly.GetExecutingAssembly() });

        var connection = new EntityConnection(workspace, _commonConnection);
        T myContextObject = (T)Activator.CreateInstance(typeof(T), new object[] { connection });
        myContextObject.Database.UseTransaction(_commonTransaction);
        return myContextObject;
    }
}