2010-01-05 37 views
14

Tôi đang lưu trữ một số dữ liệu bằng NHibernate và tôi cần chèn số lượng lớn dữ liệu như một phần của hành động này - tức là trong cùng một giao dịch. Mã trông giống như sau:Sử dụng giao thức NHibernate trong SqlBulkCopy

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

Tôi biết rằng tôi có thể sử dụng TransactionScope hoặc thực hiện theo cách khác. Nhưng tôi nhấn mạnh vào mô hình này. Hãy giả vờ rằng vì lợi ích của truy cập DB độc lập (nếu tôi trích xuất và chèn hoạt động chèn số lượng lớn tùy ý). Có cách nào để có được ví dụ SqlTransaction trong số NHibernate.ITransaction không?

Cảm ơn

+0

Câu trả lời dưới đây có giải quyết được câu hỏi của bạn không? – Meligy

Trả lời

22

Không ngạc nhiên, Ayende tackled this one as well, nhưng nó khá là grody.

Các ý chính của nó là bạn biết bạn có thể tranh thủ bình thường ADO.NET IDbCommand trường trong giao dịch NHibernate, như vậy:

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

Nhưng SqlBulkCopy không phải là một IDbCommand, và rằng nhà xây dựng nói riêng đòi hỏi phải có một SqlTransaction (vì vậy bạn đã bỏ qua thuyền trên các nhà cung cấp độc lập anyways). Vì vậy, ăn gian - ví dụ của bạn có thể trông giống như sau:

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

Chắc chắn bạn sẽ muốn một số lỗi, kiểm tra an toàn, v.v ... trong đó. Tôi không nhận thức được một cách hiện đại hơn/ít đáng sợ hơn để làm điều này, thật không may (thậm chí để có được một số IDbTransaction từ một số ITransaction).

+0

Mặc dù một chút hack, vẫn có thể gần nhất với những gì tôi cần. Làm tốt lắm! Cảm ơn. – Elephantik

0

Kiểm tra bài đăng này từ Ayene:
http://ayende.com/Blog/archive/2009/08/22/nhibernate-perf-tricks.aspx

Ông cho thấy làm thế nào bạn có thể làm điều đó bằng cả hai lựa chọn một trong hai NHibernate StatelessSession hoặc SqlBulkCopy. Nó hiển thị một mã mẫu như sau:

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

Xin lỗi nhưng tôi không thể thấy câu trả lời cho vấn đề Giao dịch. Tạo một cá thể SqlBulkCopy không phải là một vấn đề. – Elephantik

Các vấn đề liên quan