0

特定のページ (ページ ID で参照) を含むアイテムNHibernateのコレクションを取得する次のクエリを作成しました。MenuView

// 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 のページを含むメニュー項目の結果をまだ返しているのはどれですかこの単純なロジックの反転が、コードの点でそれほど単純ではないのはなぜですか?

[更新] フィーロからの提案を受けて、提案されたクエリの変更は次のようになります。

// 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 PageID = 1 の WHERE 句を使用)

結合テーブルの表示

ID が 1 のページがメニュー 5 と 6 で参照されていないことがわかります。問題のクエリは、ID が 5 のメニューの ID、名前、および説明である 1 つの行のみを返すと予想されます。ページ 1含まれ、編集可能な唯一のメニュー

代わりに、新しいクエリが返されます。

ここに画像の説明を入力

返されたすべての行を取り消しましたが、そうすべきではありません。ここで何が起こっているのですか!?

4

1 に答える 1

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>();
    
于 2012-01-03T16:14:08.273 に答える