Entity Framework中的事務問題

來源:互聯網
上載者:User

項目中試用Entity Framework1.0作為ORM層,但發現確實是問題多多,今天主要說一下其交易處理部分。

 

對於一般的單表操作,比如2個add操作要在一個事務完成,可以使用隱含交易,如:

 

TestEntities t=new TestEntities();

t.AddToTableA(t1);

t.AddToTableB(t2);

t.SaveChanges();

 

兩句語句預設是在一個事務中提交的。

 

全是單表操作的話就按以上方式沒有問題,但如果要使用預存程序,那麼問題就來了。EF1.0對於預存程序支援並不好,凡是無傳回值和傳回值為標量的預存程序,使用Function Import之後,在cs檔案雷根本找不到對應的方法,要使用預存程序需要這麼寫:

 

    TestEntities t=new TestEntities();

    t.Connection.Open();

    var tran=t.Connection.BeginTransaction();

           EntityCommand cmd2 = new EntityCommand("TestEntities.UpdateForm", t.Connection as EntityConnection, tran as EntityTransaction);
            cmd2.CommandType = CommandType.StoredProcedure;
            cmd2.Parameters.Add(new EntityParameter(...));
            cmd2.Parameters.Add(new EntityParameter(...));
            cmd2.Parameters.Add(new EntityParameter(...));
            cmd2.Parameters[0].Value = ...
            cmd2.Parameters[1].Value =...

            cmd2.Parameters[2].Value =...

            cmd2.ExecuteNonQuery();

     tran.Commit();

 

此處的UpdateForm為預存程序名稱,需要事先使用Function Import功能匯入實體模型才能使用。

同時,這裡的EntityTransaction事務可以和單表操作結合使用,比如以上代碼可以變為

 

cmd2.ExecuteNonQuery();

t.AddToTable1(t1);

t.SaveChanges();

tran.Commit();

 

那麼這個預存程序以及AddToTable1的操作是在一個事務內進行的,這是因為儘管SaveChanges()方法有自己的事務,但如果檢測到t已經開啟了現有的事務,那麼會沿用已有事務。

 

但是這樣寫有一個麻煩,entity command只支援查詢而不支援insert,update,delete,所以如果我要執行一句自訂語句update xxx set xxx where...就不行了。

 

EF Extension提供了一個擴充方法用於支援預存程序和自訂sql語句,用法如下:

 

var cmd = t.CreateStoreCommand("update form set xxx=xxx where formid=2", CommandType.Text);

var cmd = t.CreateStoreCommand("updateform", CommandType.StoredProcedure);

 

但是它使用的事務卻要求是SqlTransaction,用以下的寫法:

 

TestEntities t=new TestEntities();

t.Connection.Open();

EntityConnection con = t.Connection as EntityConnection;
var tran=con.StoreConnection.BeginTransaction();
var cmd = t.CreateStoreCommand("updateform", CommandType.StoredProcedure);

cmd.Transaction=tran;

cmd.ExecuteNonQuery();

tran.Commit();

 

注意這裡的StoreConnection,使用它建立的就是SqlTransaction。這樣的寫法可以確保在預存程序和自訂語句之間使用事務,但如果你想將一個預存程序和一個單表操作放在一起,則又會出問題。

 

cmd.ExecuteNonQuery();

t.AddToTable1(t1);

t.SaveChanges();  =》這裡會報錯!

tran.Commit();

 

 

也就是說SaveChanges()方法只認EntityTransaction,而CreateStoreCommand只認SqlTransaction,兩者無法統一。

 

所以如果要使用CreateStoreCommand方法,那麼事務內相關的所有操作都要封裝成預存程序形式,無法以單表操作進行調用;如果要使用EntityCommand+單表操作的事務,那麼就要放棄自訂Sql語句,或將他們都寫成預存程序的形式。

 

 

感謝韋恩卑鄙在評論中提供的解決方案:使用TransactionScope可以使之共存,示意代碼如下:

 

using (var dbtran = new TransactionScope(TransactionScopeOption.Required))
            {

                using (var t= new TestEntities())
                {
                     using (t.Connection.CreateConnectionScope())// EF Extension中的擴充方法,作用是open connection並在dispose裡釋放它
                    {                     

                            t.AddToTableA(t1);

                            t.SaveChanges();
                            var cmd = t.CreateStoreCommand("update form set xxx=xxx where formid=2", CommandType.Text);

          cmd.ExcuteNonQuery();

                            dbtran.Complete();
                      }

      }

    }

 

如果所有操作都是本地事務,那麼它將是一個輕型事務,不會用到MSDTC。如果是分布式的,則會自動升級為完全分散式交易,必須用到MSDTC。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.