2011-03-22 26 views
2

我對NHibernate的世界相當陌生,我似乎無法得到這個使用條件查詢的工作:查詢多對多關係或查詢實體上的集合(集合/包) 。我搜索了互聯網並檢查了我們所有的NHibernate書籍,但我無法找到針對「挑戰」的具體答案。查詢多對多集合或如何在條件查詢中包含多對多表格?

我已經做了一個簡化的例子,我試圖解決的問題。我有一張帶書籍的桌子,一張帶有類別的桌子和一本包含每本書類別的多對多桌子。下面是一些技術性的:

數據結構:

create table tableBook 
(
    BkId  integer not null default autoincrement,  
    BkTitle char(40) not null, 
    BkWriter char(40) not null, 
    primary key (BkId) 
); 

create table tableCategory 
(
    CatId  integer not null default autoincrement,  
    CatCode  char(3) not null, 
    CatDesc  char(40), 
    primary key (CatId) 
); 

create table tableCategoriesPerBook 
(
    CpbId  integer   not null default autoincrement, 
    CpbBkId  integer   not null, /*foreign key to tableBook*/ 
    CpbCatId  integer   not null, /*foreign key to tableCategory*/ 
    primary key (CpbId) 
); 

alter table tableCategoriesPerBook add foreign key FK_CpbBkId (CpbBkId) references tableBook (BkId) on update Restrict on delete Cascade; 
alter table tableCategoriesPerBook add foreign key FK_CpbCatId (CpbCatId) references tableCategory (CatId) on update Restrict on delete Cascade; 

create unique index idx_CpbCatId_CpbBkId on tableCategoriesPerBook (CpbCatId, CpbBkId); 

C#類:

public class BookEntity 
{ 
    public virtual Int32 BookId { get; set; } 
    public virtual string BookTitle { get; set; } 
    public virtual string BookWriter { get; set; } 

    private readonly IEnumerable<CategoryEntity> _categories = new ObservableCollection<CategoryEntity>(); 
    public virtual IEnumerable<CategoryEntity> Categories 
    { 
     get { return _categories; }    
    } 
} 

public class CategoryEntity 
{ 
    public virtual Int32 CategoryId { get; set; } 
    public virtual string CategoryCode { get; set; } 
    public virtual string CategoryDesc { get; set; } 
} 

NHibernate的映射:

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping namespace="Domain" assembly="Domain" xmlns="urn:nhibernate-mapping-2.2"> 
    <class name="Domain.BookEntity" table="tableBook"> 
    <id name="BookId" column="BkId" type="Int32"> 
     <generator class="native" /> 
    </id> 
    <property name="BookTitle" column="BkTitle" type="string" length="40"/> 
    <property name="BookWriter" column="BkWriter" type="string" length="40"/>  
    <idbag name="_categories" access="field" table="tableCategoriesPerBook">   
     <collection-id type="Int32" column="CpbId"> 
      <generator class="native"/> 
     </collection-id>   
     <key column="CpbBkId" property-ref="BkId"/>   
     <many-to-many column="CpbCatId" class="Domain.CategoryEntity, Domain" /> 
    </idbag> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping namespace="Domain" assembly="Domain" xmlns="urn:nhibernate-mapping-2.2"> 
    <class name="Domain.CategoryEntity" table="tableCategory">  
    <id name="CategoryId" column="CatId" type="Int32"> 
     <generator class="native" /> 
    </id> 
    <property name="CategoryCode" column="CatCode" type="string" length="3" /> 
    <property name="CategoryDesc" column="CatDesc" type="string" length="40" />  
    </class> 
</hibernate-mapping> 

我的問題:是否有可能查詢(使用ICriteria和/或分離標準)數據庫,以便我得到其中的一本書我指定的類別(例如:在catA或catB中,也可以是「和」)?我想在查詢中優化它,而不是在C#中(因爲我需要從數據庫中讀取所有書籍,然後才能根據它們的標籤集合過濾對象)。如果我手工編寫的SQL,我會產生這樣的:

SELECT * FROM tableBook                               
WHERE EXISTS 
    (
    SELECT 1 
    FROM tableCategoriesPerBook 
      INNER JOIN tableCategory on (CpbCatId = CatId and CpbBkId = BkId) 
    WHERE CatCode in ('001', '002') 
    ) 

因爲我沒有爲tableCategoriesPerBook實體,我不明白的方式來獲得該表與標準查詢。我寧可不使用添加一些手寫的一張SQL表達式:

criteria.Add(Expression.Sql("exists(.....)"); 

最後一個重要的因素:我使用的是棕地數據庫,所以我不能改變結構!這是我必須用數據庫方式進行工作。

回答

2

這很簡單。您可以使用分離標準。

DetachedCriteria bookCategoryCriteria = DetachedCriteria.For<BookEntity>("bookCat"); 
bookCategoryCriteria 
    .CreateAlias("Categories", "cat", JointType.LeftOuterJoin) 
    .Add(Restrictions.In("cat.CategoryCode", categories) 
    .Add(Restrictions.Eq("bookCat.BookId", "book.BookId") 
    .SetProjection(Projections.Id()); 

Session.CreateCriteria<BookEntity>("book") 
    .Add(Subqueries.Exists(bookCategoryCriteria)); 
+0

嗨Yads,非常感謝你的幫助。我看了很多其他的stackoverflow帖子,但沒有讓我更接近解決這個問題。你的代碼示例幾乎爲我做了! '.Add(Restrictions.Eq(「bookCat.BookId」,「book.BookId」))是不正確的,但這對我來說很容易解決,我用下面的代碼替換它:'.Add(Property.ForName(「 bookCat.BookId「)。EqProperty(」book.BookId「))'。非常感謝您的幫助。 – TedOnTheNet 2011-03-22 15:31:07