NHibernate查询,使用OfType和子查询

时间:2012-04-17 09:43:11

标签: c# nhibernate

我正在尝试编写一个NHibernate Query,它确定指定的记录是否与请求的来源相关。在这种情况下,指定的记录是客户,如果客户有来自指定来源的任何订单,则客户是相关的。

我已经开始了,但是以下查询失败了QuerySyntaxException

bool IsRelevant = Session.Query<Order>().Where
(
    ThisOrder => ThisOrder.Customer.ID == ThisCustomer.ID
    &&
    ThisOrder.Items.OfType<SourceOrderItem>().Where
    (
        I => I.Source.ID == Source.ID
    ).Count() > 0
).Count() > 0;

我认为问题的至少一部分是SourceOrderItemOrderItem的子类型,并且订单可能包含不属于该类型的项目,因此查询只需要进行额外的过滤查看正确类型的项目。

例外:

Exception of type 'Antlr.Runtime.NoViableAltException' was thrown. [.Count[Domain.Order](.Where[Domain.Order](NHibernate.Linq.NhQueryable`1[Domain.Order], Quote((R, ) => (AndAlso(Equal(R.Customer.ID, p1), GreaterThan(.Count[Domain.SourceOrderItem](.Where[Domain.SourceOrderItem](.OfType[Domain.SourceOrderItem](R.Items, ), (I, ) => (Equal(I.Source.ID, p2)), ), ), p3)))), ), )]

使用Nhibernate版本3.1.0.4000

将此更改为使用Any而不是Where().Count > 0会导致尝试运行查询的SQL异常

DECLARE @p0 int
DECLARE @p1 int
DECLARE @p2 int

SET @p0 = 1
SET @p1 = 1
SET @p2 = 1

select TOP (@p0) 
  request0_.ID as ID24_, 
  request0_.Date as Date24_, 
  request0_.Delivery as Delivery24_, 
  request0_.PO as PO24_, 
  request0_.Discount as Discount24_, 
  request0_.Notes as Notes24_, 
  request0_.PaymentType as PaymentT7_24_, 
  request0_.Transport as Transport24_, 
  request0_.Customer_id as Customer9_24_, 
  request0_.Site_id as Site10_24_, 
  request0_.CreatedBy_id as CreatedBy11_24_, 
  request0_1_.OrderNumber as OrderNum2_25_, 
  request0_2_.Revision as Revision26_, 
  request0_2_.ExpiryDate as ExpiryDate26_, 
  case 
    when request0_1_.Request_id is not null then 1 
    when request0_2_.Request_id is not null then 2 
    when request0_.ID is not null then 0 
  end as clazz_ 
from [Request] request0_ 
  left outer join [Order] request0_1_ on request0_.ID=request0_1_.Request_id 
  left outer join [Quote] request0_2_ on request0_.ID=request0_2_.Request_id 
where 
  request0_.Site_id=@p1 
  and 
  (exists 
    (select 
      items1_.ID 
     from 
       [RequestItem] items1_ 
     where request0_.ID=items1_.Request_id 
       and case 
         when items1_2_.ChargeableRequestItem_id is not null then 2 
         when items1_3_.ChargeableRequestItem_id is not null then 3 
         when items1_1_.RequestItem_id is not null then 1 
         when items1_4_.RequestItem_id is not null then 4 
         when items1_.ID is not null then 0 
       end=3 
       and items1_3_.Source_id=@p2))

这似乎在语句中缺少了很多,因为没有声明第二个case语句下面的表。

现在我通过自己编写SQL来解决这个问题。

bool IsRelevant = ((Int32)Session.CreateSQLQuery(
    "Select COUNT(*) as IsRelevant From Request\r\n" +
    "Where\r\n" +
    "   Request.Site_Id = :p0\r\n" +
    "   And Request.ID in \r\n" +
    "(\r\n" +
    "Select Request_ID From RequestItem Where ID in\r\n" +
    "   (   \r\n" +
    "   Select SourceOrderItem.ChargeableRequestItem_id\r\n" +
    "   From SourceOrderItem\r\n" +
    "   Where SourceOrderItem.Source_id = :p1\r\n" +
    "   )\r\n" +
    ")"
    ).SetParameter("p0", S.ID).SetParameter("p1", Source.ID).UniqueResult()) > 0;

虽然我仍然喜欢NHibernate解决方案。

1 个答案:

答案 0 :(得分:0)

可以通过拆分Nhibernate查询来完成此操作 e.g。

var Items = Session.Query<SourceOrderItem>().Where(I=> I.Source.ID == Source.ID).ToList();
foreach(var Item in Items)
{
    IsRelevant = Session.Query<Order>().Any(R => R.Customer.ID == C.ID && R.Items.Any(I => I.ID == Item.ID));
    if (IsRelevant)
        break;
}