2012-03-23 25 views
1
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data.SqlClient; 
using System.ComponentModel.DataAnnotations; 
using System.Data.Entity; 

namespace SqlEFTester { 
    class Program { 
     static void Main(string[] args) { 

      ConnectionManager connectionManager = new ConnectionManager(); 
      SqlConnection conn = connectionManager.Connection; 
      conn.Open(); 

      //BEGIN TRAN 
      SqlTransaction tran = conn.BeginTransaction(); 

      //Will do some legacy work using SqlTransaction, so can not use TransactionScope here. 

      MyContext context = new MyContext(conn); 
      List<Inventory> list = context.Inventories.Take(10).ToList();//Just get top 10 Inventories 

      //COMIT TRAN 
      tran.Commit(); 

      Console.WriteLine("Done..."); 
      Console.ReadLine(); 
     } 
    } 

class ConnectionManager { 
    public SqlConnection Connection { 
     get { 
      return new SqlConnection("Data Source=MYSERVER;Initial Catalog=MYDATABASE;Integrated Security=SSPI;"); 
     } 
    } 
} 

[Table("Inventory")] 
class Inventory { 
    [Key] 
    public int InventoryId { get; set; } 
} 

class MyContext : DbContext { 
    public EmutContext(SqlConnection conn) 
     : base(conn, false) { 
     //I have to close it, otherwise it will say "EntityConnection can only be constructed with a closed DbConnection." 
      base.Database.Connection.Close(); 
    } 

    public DbSet<Inventory> Inventories { get; set; } 
} 

私がやっていることは、従来のADO.NET SqlTransactionの内部でEFコードを実行することです。このSqlTransactionは完了しました。もはや使用できなくなります。エンティティフレームワークコード

私は接続を開いて、同じ接続をEFに渡して接続を再利用します。設計上、その不平から接続を閉じる必要があります

EntityConnectionは閉じたDbConnectionでのみ構築できます。

私は上記のコードを実行した場合、私は、トランザクションが完了した

を得ました。

私はコミットできません。注:私たちが使用するレガシーコードフレームワークのためにTransactionScopeを使用することはできません。

+0

(これは、SqlConnectionオブジェクトを開きます)オープンEntityConnection、その後、私はコンテキストに閉じられたSqlConnectionオブジェクトを渡していますのでご注意ください!あなたのコードでは、接続を閉じて、これはあなたのトランザクションを終了します、このようにトランザクションはコミットする前に閉じられます。 – Artem

+0

conn.Open()の直前でコンテキストを作成すると、「EntityConnectionは閉じたDbConnectionでのみ構築できます」コードラインをこのConnectionManagerのconnectionManager = new ConnectionManager()に移動します。 SqlConnection conn = connectionManager.Connection; MyContextコンテキスト=新しいMyContext(conn); conn.Open(); – sadhat75

答えて

2

私はTransactionScopeを使用する方が良いでしょうが、回避策として、リフレクションを使用することができます(おそらくもっと良い方法がありますか、わからないかもしれません)。あなたがconn.Openと呼ばれる前に、あなたはEmutContextを作成しようとしたか

 //create connection & context 
     SqlConnection sqlConnection = new SqlConnection("your connection"); 
     YourDbContext context = new YourDbContext(sqlConnection, false); 

     var entityConnection = (EntityConnection)((IObjectContextAdapter)context).ObjectContext.Connection; 
     try 
     { 
      //open entity connection - will open store connection 
      entityConnection.Open(); 

      var entityTransaction = entityConnection.BeginTransaction(); 

      //get sql transaction via reflection 
      var sqlTransaction = (SqlTransaction)entityTransaction.GetType() 
                 .InvokeMember("StoreTransaction", 
                    BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.InvokeMethod 
                    | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic, null, entityTransaction, new object[0]); 



      //here you got both sql transaction & sql connectont 
      var cmd = sqlConnection.CreateCommand(); 
      cmd.Transaction = sqlTransaction; 
      cmd.CommandText = "your sql statement"; 
      cmd.ExecuteNonQuery(); 

      //do your context work - will be in entity transaction 

      //invoke save changes 
      context.SaveChanges(); 

      entityTransaction.Commit(); 
     } 
     finally 
     { 
      entityConnection.Close(); 
     } 
+0

reflectionを使用する代わりに、次のようなものを使用しますか:((IDbCommand)cmd).Transaction = conn.BeginTransaction(); ? – Pawel

+0

@PawelこのようにSqlTransactionを作成する場合、不幸にもEntityConnectionで実行するクエリ(たとえば、作成者が記述したlinqクエリを含むコンテキストクエリ)はこのトランザクションを使用しません。同じトランザクション内でコンテキストクエリとraw SQLの両方を実行する必要がある場合は、TransactionScopeを使用する必要があります。著者はTransactionScopeを使用できないと述べたので、この小さなサンプルでEntityTransactionからSqlTransactionを取得する方法を書きました。これは同じトランザクション内でコンテキストクエリ+ raw SQLを実行することも可能にします。私は反射のためにこの方法が好きではありません。 – Artem

関連する問題