2010-01-05 51 views
14

我正在使用NHibernate存儲一些數據,並且我需要插入大量數據作爲此操作的一部分 - 即在同一個事務中。代碼如下所示:在SqlBulkCopy中使用NHibernate事務

using (ISession session = NHibernateHelper.OpenSession()) 
using (ITransaction transaction = session.BeginTransaction()) 
{ 
    session.SaveOrUpdate(something); 
    // ... 


    SqlBulkCopy bulkCopy = new SqlBulkCopy(
    (SqlConnection)session.Connection, 
    SqlBulkCopyOptions.CheckConstraints | SqlBulkCopyOptions.FireTriggers, 
    ???transaction??? 
    ); 
    //... 

    transaction.Commit(); 
} 

我知道,我可以使用的TransactionScope或做其他。但我堅持這種模式。讓我們假裝爲了獨立的數據庫訪問(如果我提取並注入任意批量插入操作)。 有沒有一種方法如何從NHibernate.ITransaction中獲得SqlTransaction實例?

感謝

+0

下面的答案是否解決了您的問題? – Meligy 2010-01-12 14:46:13

回答

22

不出所料,Ayende tackled this one as well,但它是相當grody。

它的要點是,你知道你可以在NHibernate的事務中登記正常ADO.NET IDbCommand情況下,像這樣:

var cmd = new SqlCommand(); 
if (session.Transaction != null && session.Transaction.IsActive) 
    session.Transaction.Enlist (cmd); 

SqlBulkCopy不是IDbCommand,以及特定的構造要求SqlTransaction(所以你已經跳過提供者無關的船)。所以騙 - 你的例子可能是這個樣子:

using (var session = NHibernateHelper.OpenSession()) 
using (var transaction = session.BeginTransaction()) { 
    using (var cmd = new SqlCommand()) { 
     transaction.Enlist (cmd); 

     var bulk = new SqlBulkCopy ((SqlConnection)session.Connection, 
            SqlBulkCopyOptions.CheckConstraints | SqlBulkCopyOptions.FireTriggers, 
            (SqlTransaction)cmd.Transaction); 
    } 
    // ... 
    transaction.Commit(); 
} 

你無疑會希望有一些錯誤檢查,安全鑄件等。我不知道更現代/不太可怕的方式來做到這一點,不幸的是(即使從ITransaction得到IDbTransaction)。

+0

雖然有點破解,但仍可能最接近我所需要的。做得好!謝謝。 – Elephantik 2011-10-03 14:21:29

0

檢查此帖來自Ayene:
http://ayende.com/Blog/archive/2009/08/22/nhibernate-perf-tricks.aspx

他演示瞭如何做,使用這兩種選擇要麼NHibernate的StatelessSession或使用SqlBulkCopy。它顯示了一個示例代碼:

var dt = new DataTable("Users"); 
    dt.Columns.Add(new DataColumn("Id", typeof(int))); 
    dt.Columns.Add(new DataColumn("Password", typeof(byte[]))); 
    dt.Columns.Add(new DataColumn("Username")); 
    dt.Columns.Add(new DataColumn("Email")); 
    dt.Columns.Add(new DataColumn("CreatedAt", typeof(DateTime))); 
    dt.Columns.Add(new DataColumn("Bio")); 

    for (int i = 0; i < count; i++) 
    { 
     var row = dt.NewRow(); 
     row["Id"] = i; 
     row["Password"] = Guid.NewGuid().ToByteArray(); 
     row["Username"] ="User " + i; 
     row["Email"] = i + "@example.org"; 
     row["CreatedAt"] =DateTime.Now; 
     row["Bio"] = new string('*', 128); 
     dt.Rows.Add(row); 
    } 

using (var connection = 
((ISessionFactoryImplementor)sessionFactory).ConnectionProvider.GetConnection()) 
{ 
    var s = (SqlConnection)connection; 
    var copy = new SqlBulkCopy(s); 
    copy.BulkCopyTimeout = 10000; 
    copy.DestinationTableName = "Users"; 
    foreach (DataColumn column in dt.Columns) 
    { 
     copy.ColumnMappings.Add(column.ColumnName, column.ColumnName); 
    } 
    copy.WriteToServer(dt); 
} 
+0

對不起,但我看不到交易問題的答案。創建一個SqlBulkCopy實例不是問題。 – Elephantik 2010-01-13 13:50:29