2012-01-02 72 views
0

我已经使用NHibernate构建了以下查询,它将为我提供包含给定页面(由页面id引用)的MenuView项目的集合。颠倒NHibernate查询的逻辑

// Only retrieve the required properties from Menu object 
ProjectionList menuViewProjections = Projections.ProjectionList() 
    .Add(Projections.Property("ID"), "ID") 
    .Add(Projections.Property("Name"), "Name") 
    .Add(Projections.Property("Description"), "Description"); 

var menus = session.CreateCriteria(typeof(Menu)) 
    // Only menu's that are editable 
    .Add(Restrictions.Eq("IsEditable", true)) 

    // Only project required properties 
    .SetProjection(menuViewProjections) 

    // Only menu's that contain this page (Menu object has IList<Page> property called 'Pages') 
    .CreateCriteria("Pages") 
    // Restrict to menu's containing the pages with an id of the specified value 
    .Add(Restrictions.Eq("ID", pageId)) 

    // Transform results into required, light-weight, view objects 
    .SetResultTransformer(Transformers.AliasToBean(typeof(MenuView))) 
    .List<MenuView>(); 

这工作正常;然而,现在我想做相反的事情:我想查询所有可编辑菜单对象,其中不包含包含具有指定ID的页面。迄今为止,我还没有找到解决方案。我还以为上面的查询的网页部分的简单颠倒就足够导致:

// Only retrieve the required properties from Menu object 
ProjectionList menuViewProjections = Projections.ProjectionList() 
    .Add(Projections.Property("ID"), "ID") 
    .Add(Projections.Property("Name"), "Name") 
    .Add(Projections.Property("Description"), "Description"); 

var menus = session.CreateCriteria(typeof(Menu)) 
    // Only menu's that are editable 
    .Add(Restrictions.Eq("IsEditable", true)) 

    // Only project required properties 
    .SetProjection(menuViewProjections) 

    // Only retrieve menus that do NOT contain this referenced page 
    .CreateCriteria("Pages") 
    .Add(Restrictions.Not(Restrictions.Eq("ID", pageId))) 

    // Transform results into required view objects 
    .SetResultTransformer(Transformers.AliasToBean(typeof(MenuView))) 
    .List<MenuView>(); 

但是,这会导致下面的SQL:

SELECT this_.ID   as y0_, 
    this_.Name  as y1_, 
    this_.Description as y2_ 
FROM [Menu] this_ 
     inner join PagesInMenu pages3_ 
     on this_.ID = pages3_.MenuID 
     inner join [Page] page1_ 
     on pages3_.PageID = page1_.ID 
WHERE this_.IsEditable = 1 /* @p0 */ 
     and not (page1_.ID = 8 /* @p1 */) 

这仍然是返回菜单的结果做的项目包含一个id为8的页面。为什么逻辑的这种简单逆转在代码方面并不那么简单?

[更新] 从Firo的建议,建议的查询更改;

// Only retrieve menus that do NOT contain this referenced page 
.CreateCriteria("Pages") 
.Add(Subqueries.PropertyNotIn("Id", querymenuItemswithPage)) <--- query you have would be here 

现在生成下面的sql语句;

SELECT this_.ID   as y0_, 
     this_.Name  as y1_, 
     this_.Description as y2_ 
FROM [Menu] this_ 
     inner join PagesInMenu pages3_ 
     on this_.ID = pages3_.MenuID 
     inner join [Page] page1_ 
     on pages3_.PageID = page1_.ID 
WHERE this_.IsEditable = 1 /* @p0 */ 
     and page1_.ID not in (SELECT this_0_.ID as y0_ 
          FROM [Page] this_0_ 
          WHERE this_0_.ID = 1 /* @p1 */ 

起初似乎正是我想要的,但不幸的是(可能是由于我加入的理解差)仍然没有回来完全是我想要的。给出下面的表

菜单

Shot of menu table

然后的PagesInMenu联接表(具有WHERE子句WHERE PAGEID = 1)

Show of join table

我们可以看到ID为1的页面在菜单5和6中没有被引用。我期待有问题的查询仅返回单行,这将是编号,姓名,并用5号菜单的说明,因为这是第1页是列入和编辑

相反,只有菜单新的查询返回;

enter image description here

我已经越过了被返回,但不应该成为所有行。这里发生了什么 !?

+0

,因为它从一个变化 “一项在网页符合条件”,以“在页面比赛的所有项目条件“ – Firo 2012-01-03 13:01:14

回答

1

更新:

  • 去除.CreateCriteria("Pages")
  • 添加子查询

    var querymenuItemswithPage = DetachedCriteria.For<Menu>() 
    .CreateCriteria("Pages") 
        .Add(Restrictions.Eq("ID", pageId)) 
    .SetProjection(Projections.Id()) 
    
    // Only retrieve the required properties from Menu object 
    ProjectionList menuViewProjections = Projections.ProjectionList() 
        .Add(Projections.Property("ID"), "ID") 
        .Add(Projections.Property("Name"), "Name") 
        .Add(Projections.Property("Description"), "Description"); 
    
    var menus = session.CreateCriteria(typeof(Menu)) 
        // Only menu's that are editable 
        .Add(Restrictions.Eq("IsEditable", true)) 
    
        // Only project required properties 
        .SetProjection(menuViewProjections) 
    
        // Only retrieve menus that do NOT contain this referenced page 
        .Add(Subqueries.PropertyNotIn("Id", querymenuItemswithPage)) 
    
        // Transform results into required view objects 
        .SetResultTransformer(Transformers.AliasToBean(typeof(MenuView))) 
        .List<MenuView>(); 
    
+0

”限制“对象没有.Property之类的东西。有些东西,比如EqProperty,LeProperty,GtProperty等,但没有一个将字符串作为参数。 – user407356 2012-01-03 18:47:01

+0

对我编辑,它是子查询和PropertyNotIn – Firo 2012-01-03 23:40:42

+0

感谢您将此问题转移一点,请参阅编辑信息 – user407356 2012-01-08 11:51:53