想象一下以下(简化)数据库布局:
我们有许多“假期”记录,这些记录与在特定日期等特定住宿有关。
我想从数据库中提取每个住宿的“最佳”假期(即最低价格),给定一组搜索标准(例如,持续时间,出发机场等)。
将有多个具有相同价格的记录,因此我们需要选择保存(降序),然后按出发日期升序。
我可以编写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
如您所见,这在另一个子查询中使用子查询。
但是,出于几个原因,我倾向于在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;
}
所以我的问题是......
关于如何使用QueryOver实现我想要的任何想法,或者必要时使用Criteria API?
我不想使用HQL,但是如果有必要的话,我也不愿意看到它是如何做到的那样(这使得建立搜索标准变得更难(或更麻烦))。
如果使用NHibernate这是不可行的,那么我可以使用SQL查询。在这种情况下,我的问题是可以改进/优化SQL吗?
答案 0 :(得分:1)
我已经设法通过使用Criteria API来实现这种动态搜索条件。我遇到的问题是内部和外部联接的重复,特别是与排序和分页相关,我不得不求助于使用2个查询,第一个查询限制并将第一个查询的结果用作第二个creteria中的“in”子句。 / p>