【问题标题】:NHibernate - joining on a subquery using ICriteriaNHibernate - 使用 ICriteria 加入子查询
【发布时间】:2009-05-13 04:57:41
【问题描述】:

我有一个需要使用 NHibernate 的 ICriteria API 表示的 SQL 查询。

   SELECT u.Id as Id, 
    u.Login as Login, 
    u.FirstName as FirstName, 
    u.LastName as LastName, 
    gm.UserGroupId_FK as UserGroupId,
    inner.Data1,
    inner.Data2,
    inner.Data3
    FROM dbo.User u inner join 
    dbo.GroupMember gm on u.Id = gm.UserAnchorId_FK 
    left join
    (
        SELECT
        di.UserAnchorId_FK,
        sum(di.Data1) as Data1, 
        sum(di.Data2) as Data2, 
        sum(di.Data3) as Data3
        FROM
        dbo.DailyInfo di 
        WHERE di.Date between '2009-04-01' and '2009-06-01' 
        GROUP BY di.UserAnchorId_FK
    ) inner ON inner.UserAnchorId_FK = u.Id
    WHERE gm.UserGroupId_FK = 195 

迄今为止的尝试包括映射“User”和“DailyInfo”类(我的实体)以及使 DailyInfo 对象成为 User 对象的属性。但是,如何映射它们之间的外键关系仍然是一个谜,即

<one-to-one></one-to-one>

<one-to-many></one-to-many>

<generator class="foreign"><param name="property">Id</param></generator> (!) 

网络上的解决方案通常与 WHERE 子句中的子查询有关,但是我需要在此子查询上左连接,以确保为未连接的行返回 NULL 值。

我觉得我应该为外部查询使用 Criteria,然后用 DetachedCriteria 形成一个“join”来表示子查询?

【问题讨论】:

    标签: c# sql nhibernate subquery icriteria


    【解决方案1】:

    我遇到了同样的问题,但我没有得到任何解决方案。所以我用拦截器做了一个 hack

    按条件生成的查询

    SELECT u.Id as Id, 
    u.Login as Login, 
    u.FirstName as FirstName, 
    u.LastName as LastName, 
    gm.UserGroupId_FK as UserGroupId,
    inner.Data1,
    inner.Data2,
    inner.Data3
    FROM dbo.User u inner join 
    dbo.GroupMember gm on u.Id = gm.UserAnchorId_FK 
    InnerJoin inner ON inner.UserAnchorId_FK = u.Id
    WHERE gm.UserGroupId_FK = 195
    

    这里的 InnerJoin 是一个与 User 有 1-1 关系的虚拟表。 InnerJoin 中的列是内连接子查询的返回值

    用户和 InnerJoin 的标准

    DetachedCriteria forUser = DetachedCriteria.For<User>();
    forUser.CreateCriteria("InnerJoin");
    

    现在你可以制作拦截器来编辑查询

    public interface CustomInterceptor : IInterceptor, EmptyInterceptor
    {    
     SqlString IInterceptor.OnPrepareStatement(SqlString sql)
     {
        string query = sql.ToString();
         if (query.Contains("InnerJoin "))
         {
            sql = sql.Replace("InnerJoin ", "(select [vals] form dbo.DailyInfo [where conditions])");
         }
         return sql;
     }
    }
    

    对于来自多个表的返回值,包括连接的子查询,您必须使用 NHibernate DTO 而会话是这样的

    CustomInterceptor custonInterceptor=new CustomInterceptor(); 
    
    sessionFactory.OpenSession(custonInterceptor);
    

    最终的查询将是您想要得到的结果

    【讨论】:

      【解决方案2】:

      就映射关系而言,听起来您在 User 和 DailyInfo 之间存在一对多的关系:

      <!-- User mapping -->
      <bag name="DailyInfos" inverse="true">
          <key column="UserAnchorId_FK" />
          <one-to-many class="Namespace.To.DailyInfo, Namespace" />
      </bag>
      
      <!-- DailyInfo mapping -->
      <many-to-one name="User" column="UserAnchorId_FK" />
      

      至于其余的,我目前不完全确定...听起来您可能通过GroupMember 表在UserGroup 之间存在多对多,这可能是一个复杂的因素。请记住,您可以对条件执行.CreateCriteria("Association path", jointype) 以创建具有指定连接类型的子条件。发布您的类/表关系的概要可能会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多