我正在尝试构建一个nHibernate条件表达式来执行搜索。
鉴于以下数据模型:
我想根据以下标准搜索所有会话:
o(可选)以及操作状态/结束日期在用户指定的日期范围内
o(可选)以及会话regionid与用户指定的id
匹配的位置o(可选)以及会话分区与用户指定的id
匹配的位置o(可选)以及Operation.OperationTypes在用户指定的类型ID列表中的位置
我会在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表达式吗?
答案 0 :(得分:5)
我假设OperationType
是实体类(不是枚举)。您不能将In
与实体列表一起使用。您可以使用ID加入。
criteria
.CreateCriteria("Operation")
// add other expressions
.CreateCriteria("OperationTypes", "operationTypes", JoinType.LeftOuterJoin)
.Add(Expression.In("operationTypes.Id", operationTypeId))
我假设_session.Get(id)执行数据库查询。无论如何你应该避免这种情况。
PS:如果将OperationType映射为复合集合(带有<composite-element>
标记),则遗憾的是,您无法将其与条件一起加入。我不确定是否有解决方法。但是有一个补丁未决。
答案 1 :(得分:1)
我认为有一种比写作更好的方法:
criteria
.CreateCriteria("Operation")
// add other expressions
.CreateCriteria("OperationTypes", "operationTypes", JoinType.LeftOuterJoin)
.Add(Expression.In("operationTypes.Id", operationTypeId))
因为在"Operation"
您可以简单地写一下:
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())