在SqlBulkCopy中使用NHibernate事务

我正在使用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或以其他方式使用它。 但我坚持这种模式。 让我们假装为了独立的DB访问(如果我提取并注入任意批量插入操作)。 有没有办法如何从NHibernate.ITransaction获取SqlTransaction实例?

谢谢

不出所料,Ayende也解决了这个问题 ,但它非常可笑。

它的要点是你知道你可以在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 )。

查看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); }