Эта SqlTransaction завершена;это больше не годится для использования.Entity Framework Code First - PullRequest
1 голос
/ 23 марта 2012
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; }
}

Я пытаюсь выполнить код EF внутри традиционного ADO.NET SqlTransaction.

Я открываю соединение и передаю то же соединение в EF, чтобы повторно использовать соединение.По замыслу я должен закрыть соединение, так как его жалоба

EntityConnection может быть создана только с закрытым DbConnection.

Если я запускаю выше кода, я получил

Транзакция завершена.

Я не могу зафиксировать.ПРИМЕЧАНИЕ. Я не могу использовать TransactionScope из-за устаревшей структуры кода, которую мы используем.

1 Ответ

2 голосов
/ 24 марта 2012

Хорошо, я бы лучше использовал TransactionScope, но в качестве обходного пути вы можете попытаться использовать отражение (возможно, есть лучший способ, не уверен). Обратите внимание, что я передаю закрытое SqlConnection в контекст, затем открываю EntityConnection (откроется SqlConnection)

        //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();
        }
...