Фильтр объединений в nHibernate
Я пытаюсь создать выражение критерия nHibernate для выполнения поиска.
Учитывая следующую модель данных:
- У операции может быть ноль или более сеансов.
- Операция может иметь нулевое или большее количество типов операций.
Я хочу найти все сеансы по следующим критериям:
- (Обязательно) Если флаг IsActive операции имеет значение true, флаг IsPublished имеет значение true.
o (Необязательно), и где состояние операции / даты окончания находятся в указанном пользователем диапазоне дат
o (Необязательно) и где идентификатор региона сеанса совпадает с идентификатором, указанным пользователем
o (Необязательно) и где разделение сеанса соответствует указанному пользователем идентификатору
o (Необязательно) и где Operation.OperationTypes находятся в заданном пользователем списке идентификаторов типов
Я бы выразил это в sql как (с учетом всех дополнительных параметров):
SELECT
[Session].*
FROM
[OperationTypeOperation]
LEFT OUTER JOIN
[Operation] ON [OperationTypeOperation].[OperationId] = [Operation].[OperationId]
RIGHT OUTER JOIN
[Session] ON [Operation].[OperationId] = [Session].[OperationId]
WHERE
([Operation].[IsPublished] = 1)
AND
([Operation].[IsActive] = 1)
AND
([Session].[RegionId] = 66)
AND
([Session].[DivisionId] = 99)
AND
([Operation].[AdvertisingStartDate] < GETDATE())
AND
([Operation].[AdvertisingEndDate] > GETDATE())
AND
([OperationTypeOperation].[OperationTypeId] IN (1, 2, 3))
И в моем запросе nHibernate как:
public PagedResult<Session> Search(int? regionId, int? divisionId, DateTime? startDate, DateTime? endDate, IList<int> operationTypeId, int itemsPerPage, int page)
{
var criteria = _session.CreateCriteria(typeof(Session))
.Add(Expression.Eq("IsActive", true))
.Add(Expression.Eq("AcceptingApplications", true))
.AddOrder(new Order("StartDate", false))
;
if (regionId.HasValue)
criteria.Add(Expression.Eq("Region.Id", regionId.Value));
if (divisionId.HasValue)
criteria.Add(Expression.Eq("Division.Id", divisionId.Value));
if (startDate.HasValue)
criteria.Add(Expression.Ge("StartDate", startDate.Value));
if (endDate.HasValue)
criteria.Add(Expression.Le("EndDate", endDate.Value));
//Add the operation types
if (operationTypeId.Count > 0)
{
var operationTypes = new Collection<OperationType>();
foreach (int id in operationTypeId)
{
operationTypes.Add(_session.Get<OperationType>(id));
}
//Join on the operations
criteria.CreateCriteria("Operation")
.Add(Expression.Eq("IsPublished", true))
.Add(Expression.Eq("IsActive", true))
.Add(Expression.Le("AdvertisingStartDate", DateTime.Now))
.Add(Expression.Ge("AdvertisingEndDate", DateTime.Now))
.CreateAlias("OperationTypes", "operationTypes", JoinType.InnerJoin)
.Add(Expression.In("OperationTypes", operationTypes))
.SetResultTransformer(new DistinctRootEntityResultTransformer())
;
}
else
{
//Join on the operations
criteria.CreateCriteria("Operation")
.Add(Expression.Eq("IsPublished", true))
.Add(Expression.Eq("IsActive", true))
.Add(Expression.Le("AdvertisingStartDate", DateTime.Now))
.Add(Expression.Ge("AdvertisingEndDate", DateTime.Now))
;
}
return criteria.ToPagedResult<Session>(itemsPerPage, page);
}
Моя функция nHibernate жалуется на типы операций и выдает исключение «Невозможно использовать коллекции с InExpression». Кроме того, я не уверен, правильно ли я фильтрую объединенные таблицы. Может ли кто-нибудь правильно взвесить, чтобы написать вышеуказанный sql как выражение nHibernate?
Ответов (2)2
Я предполагаю, что OperationType
это класс сущности (а не перечисление). Вы не можете использовать In
со списком сущностей. Вы можете присоединиться, используя идентификатор.
criteria
.CreateCriteria("Operation")
// add other expressions
.CreateCriteria("OperationTypes", "operationTypes", JoinType.LeftOuterJoin)
.Add(Expression.In("operationTypes.Id", operationTypeId))
Я предполагаю, что _session.Get (id) выполняет запрос к базе данных. В любом случае вам следует избегать этого.
PS: Если OperationType отображается как составная коллекция (с <composite-element>
тегом), то, к сожалению, вы не можете присоединиться к ней с критериями. Я не уверен, есть ли обходной путь. Но есть патч на рассмотрении.
I think there is a better way than writing :
criteria
.CreateCriteria("Operation")
// add other expressions
.CreateCriteria("OperationTypes", "operationTypes", JoinType.LeftOuterJoin)
.Add(Expression.In("operationTypes.Id", operationTypeId))
because additional join is performed on "Operation"
You can simply write:
criteria.Add(Expression.In("OperationTypes", operationTypeId))
.CreateCriteria("Operation")
.Add(Expression.Eq("IsPublished", true))
.Add(Expression.Eq("IsActive", true))
.Add(Expression.Le("AdvertisingStartDate", DateTime.Now))
.Add(Expression.Ge("AdvertisingEndDate", DateTime.Now))
.SetResultTransformer(new DistinctRootEntityResultTransformer())