是否可以使用`SqlDbType.Structured` 在NHibernate 中传递表值参数?

我想将一组 id 传递给将使用 NHibernate 映射的存储过程.这种技术是在 Sql Server 2008 中引入的(更多信息在这里=> 表值参数).我只是不想在 nvarchar 参数中传递多个 id,然后在 SQL Server 端截断它的值.

I want to pass a collection of ids to a stored procedure that will be mapped using NHibernate. This technique was introduced in Sql Server 2008 ( more info here => Table-Valued Parameters ). I just don't want to pass multiple ids within an nvarchar parameter and then chop its value on the SQL Server side.

推荐答案

我的第一个临时想法是实现我自己的 IType.

My first, ad hoc, idea was to implement my own IType.

public class Sql2008Structured : IType {
    private static readonly SqlType[] x = new[] { new SqlType(DbType.Object) };
    public SqlType[] SqlTypes(NHibernate.Engine.IMapping mapping) {
        return x;
    }

    public bool IsCollectionType {
        get { return true; }
    }

    public int GetColumnSpan(NHibernate.Engine.IMapping mapping) {
        return 1;
    }

    public void NullSafeSet(DbCommand st, object value, int index, NHibernate.Engine.ISessionImplementor session) {
        var s = st as SqlCommand;
        if (s != null) {
            s.Parameters[index].SqlDbType = SqlDbType.Structured;
            s.Parameters[index].TypeName = "IntTable";
            s.Parameters[index].Value = value;
        }
        else {
            throw new NotImplementedException();
        }
    }

    #region IType Members...
    #region ICacheAssembler Members...
}

没有更多的方法被实现;throw new NotImplementedException(); 在所有其余部分.接下来,我为 IQuery 创建了一个简单的扩展.

No more methods are implemented; a throw new NotImplementedException(); is in all the rest. Next, I created a simple extension for IQuery.

public static class StructuredExtensions {
    private static readonly Sql2008Structured structured = new Sql2008Structured();

    public static IQuery SetStructured(this IQuery query, string name, DataTable dt) {
        return query.SetParameter(name, dt, structured);
    }
}

我的典型用法是

DataTable dt = ...;
ISession s = ...;
var l = s.CreateSQLQuery("EXEC some_sp @id = :id, @par1 = :par1")
            .SetStructured("id", dt)
            .SetParameter("par1", ...)
            .SetResultTransformer(Transformers.AliasToBean<SomeEntity>())
            .List<SomeEntity>();

好的,但是什么是 "IntTable"?它是为传递表值参数而创建的 SQL 类型的名称.

Ok, but what is an "IntTable"? It's the name of SQL type created to pass table value arguments.

CREATE TYPE IntTable AS TABLE
(
    ID INT
);

some_sp 可能就像

CREATE PROCEDURE some_sp
    @id IntTable READONLY,
    @par1 ...
AS
BEGIN
...
END

它当然只适用于 Sql Server 2008,在这个特殊的实现中使用单列 DataTable.

It only works with Sql Server 2008 of course and in this particular implementation with a single-column DataTable.

var dt = new DataTable();
dt.Columns.Add("ID", typeof(int));

它只是 POC,不是一个完整的解决方案,但它可以工作并且在定制时可能有用.如果有人知道更好/更短的解决方案,请告诉我们.

It's POC only, not a complete solution, but it works and might be useful when customized. If someone knows a better/shorter solution let us know.

相关文章