Фильтр 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();
Другие вопросы по тегам