Фильтр FluentNHibernate с параметризованным предложением IN
В Fluent NHibernate возможно ли добавить параметр в фильтр типа List<int>
так что условие фильтра генерирует WHERE SomeColumn IN (@x, @y, @z)
?
Мой вариант использования заключается в получении счета-фактуры и подмножества его строк с учетом идентификатора счета-фактуры и списка номеров строк счета-фактуры. Я хочу получить строки в ту же туда и обратно, что и счет-фактура. Я предполагаю, что это сделано примерно так, но я не могу найти правильное объявление типа для параметра типа:
Доменные объекты:
public class Invoice {
public int Id {get;set;}
public List<InvoiceLine> Lines {get;set;}
}
public class InvoiceLine {
public int Id {get;set}
public int LineNumber {get;set;}
}
Отображения:
public class InvoiceMap : ClassMap<Invoice> {
public InvoiceMap() {
Id(x => x.Id);
HasMany(x => x.Lines).ApplyFilter<OnlyLinesWithNumbersFilter>();
}
}
public class InvoiceLineMap : ClassMap<InvoiceLine> {
public InvoiceLineMap() {
Id(x => x.Id);
Map(x => x.LineNumber);
}
}
Определение фильтра:
public class OnlyLinesWithNumbersFilter : FilterDefinition
{
public OnlyLinesWithNumbersFilter()
{
WithName("OnlyLinesWithNumbers");
WithCondition("LineNumber IN (:LineNumbers)");
AddParameter("LineNumbers",?? What to put here ??);
}
}
Запрос:
var filterName = "OnlyLinesWithNumbers";
session.EnableFilter(filterName).SetParameterList("LineNumbers", new[] {1,2,3});
var query = session.QueryOver<Invoice>()
.Where(i => i.Id == 42)
.Fetch(i => i.Lines).Eager
.TransformUsing(new DistinctRootEntityResultTransformer());
var result = query.SingleOrDefault();
session.DisableFilter(filterName);
4 ответа
Take-2
InvoiceLine invoiceLineAlias = null;
var list = session.QueryOver<Invoice>()
.Where(x => x.Id == 1)
.JoinQueryOver(x => x.Lines, () => invoiceLineAlias, JoinType.LeftOuterJoin)
.WhereRestrictionOn(() => invoiceLineAlias.LineNumber)
.IsIn(new List<int> { 1, 2, 3 })
.List();
производится sql:
SELECT
this_.Id as Id2_1_,
invoicelin1_.Invoice_id as Invoice3_3_,
invoicelin1_.Id as Id3_,
invoicelin1_.Id as Id3_0_,
invoicelin1_.LineNumber as LineNumber3_0_
FROM
"Invoice" this_
left outer join
"InvoiceLine" invoicelin1_
on this_.Id=invoicelin1_.Invoice_id
WHERE
this_.Id = @p0
and invoicelin1_.LineNumber in (
@p1, @p2, @p3
);
@p0 = 1 [Type: Int32 (0)],
@p1 = 1 [Type: Int32 (0)],
@p2 = 2 [Type: Int32 (0)],
@p3 = 3 [Type: Int32 (0)]
Чтобы использовать фильтры NHibernate с массивами, поместите NHibernateUtil.Int32 в метод AddParameter, сделайте так:
public class OnlyLinesWithNumbersFilter : FilterDefinition
{
public OnlyLinesWithNumbersFilter()
{
WithName("OnlyLinesWithNumbers");
WithCondition("LineNumber IN (:LineNumbers)");
AddParameter("LineNumbers", NHibernateUtil.Int32);
}
}
И когда вы включили фильтр, установите массив в SetParameterList
int[] lines = new int[] {1, 2, 3};
session.EnableFilter("OnlyLinesWithNumbers").SetParameterList("LineNumbers", lines);
В своих тестах я использую NHibernate 4.0.0.400
Ты можешь написать
var list = session.QueryOver<Invoice>()
.WhereRestrictionOn(p => p.SomeColumn)
.IsIn(someList)
.List();
Я думаю, что это правильный синтаксис, я просто написал это на макушке.:)
InvoiceLine invoiceLine = null;
var result = session.QueryOver<Invoice>()
.Where(x => x.Id == 42)
.JoinQueryOver(x => x.InvoiceLines, () => invoiceLine)
.WhereRestrictionOn(x => x.ItemNumber)
.IsIn(new[] {1, 2, 3})
.SingleOrDefault();