Pratik
Pratik

Reputation: 888

Share connection between DbContext objects in Entity Framework 6 Database first approach

I am trying to share a connection in between 2 different DB context objects using EF 6 . I have got the code mentioned here https://msdn.microsoft.com/en-us/data/dn456843.aspx to work for a single DB Context but as soon as I try to share the connection with another DB Context object I am running into trouble. Below is what I have done so for.

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;
            }
}

The code for generation of connection string is mentioned below:

string GenerateConnectionString()
{
            var entityBuilder = new EntityConnectionStringBuilder
            {
                Provider = "System.Data.SqlClient",                     
                ProviderConnectionString = SharedDatabase.SQLBase.DBconnection + "multipleactiveresultsets=True;" ,
                Metadata = @"res://*/;"
            };

       return entityBuilder ;
}

I can then call the GetDbContext from different places in my function like so

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


}

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

}

Because I am using the generic metadata portion , I am getting errors in entity framework "cannot have more than one entity with same name regardless of the namespace"

However if I specify the name of the .csdl/.ssdl file , the connection ( and hence the transaction ) can no more be common and I have to create a connection and Transaction for each DBContext ( this is what i wanted to avoid )

It seems I have hit a block . Is there a way for me to use the same connection without getting the duplicate entities error ? Changing the names of entities to be different is not an option for me as it will be a very time consuming change which I would have to do across 30 + db context / EDMX files with huge production impact.

Upvotes: 2

Views: 3804

Answers (1)

Guillaume
Guillaume

Reputation: 13128

As seen in Working with Transactions (EF6 Onwards), use the following code to provide an existing transaction to your context :

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;
    }
}

Upvotes: 4

Related Questions