我已經使用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 */
)
起初似乎正是我想要的,但不幸的是(可能是由於我加入的理解差)仍然沒有回來完全是我想要的。給出下面的表
菜單
然後的PagesInMenu聯接表(具有WHERE子句WHERE PAGEID = 1)
我們可以看到ID爲1的頁面在菜單5和6中沒有被引用。我期待有問題的查詢僅返回單行,這將是編號,姓名,並用5號菜單的說明,因爲這是第1頁是不列入和是編輯
相反,只有菜單新的查詢返回;
我已經越過了被返回,但不應該成爲所有行。這裏發生了什麼 !?
,因爲它從一個變化 「一項在網頁符合條件」,以「在頁面比賽的所有項目條件「 – Firo 2012-01-03 13:01:14