Note that there are some explanatory texts on larger screens.

plurals
  1. POReversing the logic of NHibernate query
    primarykey
    data
    text
    <p>I have constructed the following query using <code>NHibernate</code> which will give me a collection of <code>MenuView</code> items which contain a given page (referenced by the pages id).</p> <pre><code>// 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&lt;Page&gt; 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&lt;MenuView&gt;(); </code></pre> <p>This works fine; however, now I want to do the opposite: I want to query for all editable menu objects that <strong>do not</strong> contain the page with specified ID. I have thus far not found a solution for this. I would have thought a simple reversal of the pages section of the above query would suffice resulting in:</p> <pre><code>// 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&lt;MenuView&gt;(); </code></pre> <p>But, this results in the following SQL:</p> <pre><code>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 */) </code></pre> <p>Which is still returning results of Menu items that <strong>do</strong> contain a page with id of 8. Why is this simple reversal of logic not so simple in terms of code?</p> <p><strong>[Update]</strong> Taking on the suggestions from Firo, the suggested query alteration to;</p> <pre><code>// Only retrieve menus that do NOT contain this referenced page .CreateCriteria("Pages") .Add(Subqueries.PropertyNotIn("Id", querymenuItemswithPage)) &lt;--- query you have would be here </code></pre> <p>Now generates the following sql statement;</p> <pre><code> 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 */ </code></pre> <p>)</p> <p>Which at first seems exactly what I wanted but sadly (probably due to my poor understanding of joins) is still not returning quite what I wanted. Given the following tables</p> <p><strong>Menu</strong></p> <p><img src="https://i.stack.imgur.com/6g1nC.png" alt="Shot of menu table"></p> <p>And then the join-table of <strong>PagesInMenu</strong> (with a WHERE clause of WHERE PageID = 1)</p> <p><img src="https://i.stack.imgur.com/jzRPh.png" alt="Show of join table"></p> <p>We can see that page with id of 1 is NOT referenced in menus 5 and 6. I expect the query in question to only return a single row, which would be the ID, Name and Description of Menu with ID of 5 as this is the only menu which page 1 is <strong>not</strong> included in and which <strong>is</strong> editable</p> <p>Instead, the new query returns;</p> <p><img src="https://i.stack.imgur.com/8UEiX.png" alt="enter image description here"></p> <p>I have crossed out all the rows that are returned but shouldnt be. What is going on here !?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload