Можно ли использовать ' SqlDbType.Structured ' для передачи табличных параметров в NHibernate?
Я хочу передать коллекцию идентификаторов хранимой процедуре, которая будет сопоставлена с помощью NHibernate. Этот метод был введен в Sql Server 2008 ( дополнительная информация здесь => Табличные Параметры ). Я просто не хочу передавать несколько идентификаторов в nvarchar
параметр, а затем измельчите его значение на стороне SQL Server.
4 ответов
моя первая, специальная, идея заключалась в реализации моей собственной 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(IDbCommand 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...
}
никакие другие методы не реализованы; a throw new NotImplementedException();
есть во всем остальном. Затем я создал простое расширение для 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, созданного для передачи аргументов табличного значения.
CREATE TYPE IntTable AS TABLE
(
ID INT
);
и some_sp
может быть как
CREATE PROCEDURE some_sp
@id IntTable READONLY,
@par1 ...
AS
BEGIN
...
END
он работает только с Sql Сервер 2008, конечно, и в этой конкретной реализации с одним столбцом DataTable
.
var dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
это только POC, а не полное решение, но оно работает и может быть полезно при настройке. Если кто-то знает лучшее/более короткое решение, сообщите нам об этом.
более простое решение, чем принято ответ будет использовать ADO.NET. NHibernate на позволяет привлечь IDbCommands
в транзакции NHibernate.
DataTable myIntsDataTable = new DataTable();
myIntsDataTable.Columns.Add("ID", typeof(int));
// ... Add rows to DataTable
ISession session = sessionFactory.GetSession();
using(ITransaction transaction = session.BeginTransaction())
{
IDbCommand command = new SqlCommand("StoredProcedureName");
command.Connection = session.Connection;
command.CommandType = CommandType.StoredProcedure;
var parameter = new SqlParameter();
parameter.ParameterName = "IntTable";
parameter.SqlDbType = SqlDbType.Structured;
parameter.Value = myIntsDataTable;
command.Parameters.Add(parameter);
session.Transaction.Enlist(command);
command.ExecuteNonQuery();
}
вы можете передавать коллекции значений без хлопот.
пример:
var ids = new[] {1, 2, 3};
var query = session.CreateQuery("from Foo where id in (:ids)");
query.SetParameterList("ids", ids);
NHibernate создаст параметр для каждого элемента.
другие получили эту реализацию для работы? Мне нужно передать несколько строк из нескольких столбцов( 5 целых чисел, чтобы быть точным) с помощью этого метода– я определил свой базовый структурированный тип SQL и изменил ColumnSpan
вернуться 5. Единственное отличие, которое я вижу, заключается в том, что я не возвращаю значения в выполнении хранимой процедуры. Он просто потребляет поставляемые ему ценности.
DataTable dt = ...;
var query = session.CreateSqlQuery("EXEC foo_proc_here @data = :data")
.SetStructured("data", dt)
.ExecuteUpdate();
к сожалению, это вызывает " не удалось выполнить собственный запрос массовой манипуляции" сообщение. Внутренние исключения жалуются на ошибки "индекс вне диапазона".
Я не совсем уверен, куда даже обратиться дальше, так как тема структурированных типов / параметров значений таблицы с NHibernate кажется достаточно эзотерической, что я продолжаю заканчивать на этом же переполнении стека.