2012-01-02 49 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