在SqlBulkCopy中使用NHibernate事务

时间:2010-01-05 12:42:42

标签: c# sql-server nhibernate ado.net transactions

我正在使用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访问(如果我提取并注入任意批量插入操作)。 有没有办法从SqlTransaction中获取NHibernate.ITransaction个实例?

由于

2 个答案:

答案 0 :(得分:23)

不出所料,Ayende tackled this one as well,但它非常可笑。

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

毫无疑问,你需要在那里进行一些错误检查,安全演员表等。不幸的是,我不知道有更现代/更不可怕的方法(即使从IDbTransaction获得ITransaction)。

答案 1 :(得分: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);
}