如何使用NHibernate QueryOver重新创建这个复杂的SQL查询?

Chr*_*nes 41 nhibernate subquery queryover

想象一下以下(简化)数据库布局: 数据库布局

我们有许多"假期"记录,涉及在特定日期前往特定住宿等.

我想从数据库中提取每个住宿的"最佳"假期(即最低价格),给定一组搜索标准(例如持续时间,出发机场等).

将有多个具有相同价格的记录,因此我们需要选择保存(降序),然后按出发日期升序.

我可以写SQL来做这个看起来像这样(我不是说这必然是最优化的方式):

SELECT *
FROM Holiday h1 INNER JOIN (

    SELECT  h2.HolidayID,
        h2.AccommodationID,
        ROW_NUMBER() OVER (
            PARTITION BY h2.AccommodationID
            ORDER BY OfferSaving DESC
        ) AS RowNum
    FROM Holiday h2 INNER JOIN (

        SELECT  AccommodationID,
            MIN(price) as MinPrice
        FROM Holiday
        WHERE TradeNameID = 58001
        /*** Other Criteria Here ***/
        GROUP BY AccommodationID

    ) mp
    ON mp.AccommodationID = h2.AccommodationID
    AND mp.MinPrice = h2.price
    WHERE TradeNameID = 58001
    /*** Other Criteria Here ***/

) x on h1.HolidayID = x.HolidayID and x.RowNum = 1
Run Code Online (Sandbox Code Playgroud)

如您所见,这在另一个子查询中使用子查询.

但是,出于几个原因,我倾向于在NHibernate中实现相同的结果.

理想情况下,这将使用QueryOver完成 - 原因是我动态地构建了搜索条件,而使用QueryOver的流畅界面则更容易.(我开始希望使用NHibernate Linq,但不幸的是它还不够成熟).

经过很多努力(作为NHibernate的相对新手),我能够重新创建获取所有住宿及其最低价格的内部查询.

public IEnumerable<HolidaySearchDataDto> CriteriaFindAccommodationFromPricesForOffers(IEnumerable<IHolidayFilter<PackageHoliday>> filters, int skip, int take, out bool hasMore)
    {
        IQueryOver<PackageHoliday, PackageHoliday> queryable = NHibernateSession.CurrentFor(NHibernateSession.DefaultFactoryKey).QueryOver<PackageHoliday>();

        queryable = queryable.Where(h => h.TradeNameId == website.TradeNameID);

        var accommodation = Null<Accommodation>();
        var accommodationUnit = Null<AccommodationUnit>();
        var dto = Null<HolidaySearchDataDto>();

        // Apply search criteria
        foreach (var filter in filters)
            queryable = filter.ApplyFilter(queryable, accommodationUnit, accommodation);

        var query1 = queryable

            .JoinQueryOver(h => h.AccommodationUnit, () => accommodationUnit)
            .JoinQueryOver(h => h.Accommodation, () => accommodation)
            .SelectList(hols => hols
                                    .SelectGroup(() => accommodation.Id).WithAlias(() => dto.AccommodationId)
                                    .SelectMin(h => h.Price).WithAlias(() => dto.Price)
            );

        var list = query1.OrderByAlias(() => dto.Price).Asc
            .Skip(skip).Take(take+1)
            .Cacheable().CacheMode(CacheMode.Normal).List<object[]>();

        // Cacheing doesn't work this way...
        /*.TransformUsing(Transformers.AliasToBean<HolidaySearchDataDto>())
        .Cacheable().CacheMode(CacheMode.Normal).List<HolidaySearchDataDto>();*/

        hasMore = list.Count() == take;

        var dtos = list.Take(take).Select(h => new HolidaySearchDataDto
                    {
                        AccommodationId = (string)h[0],
                        Price = (decimal)h[1],
                    });

        return dtos;
    }
Run Code Online (Sandbox Code Playgroud)

所以我的问题是......

关于如何使用QueryOver实现我想要的任何想法,或者必要的Criteria API?

我不想使用HQL但是如果有必要的话我也不愿意看到它是如何做到的那样(它使得建立搜索标准变得更难(或更麻烦)).

如果使用NHibernate这是不可行的,那么我可以使用SQL查询.在这种情况下,我的问题是可以改进/优化SQL吗?

Ami*_*mit 1

我已经通过使用 Criteria API 成功实现了这种动态搜索标准。我遇到的问题是内部和外部联接的重复,尤其是与排序和分页相关的问题,我不得不求助于使用 2 个查询,第一个查询进行限制,并使用第一个查询的结果作为第二个 creteria 中的“in”子句。