Abfragen einer Viele-zu-Viele-Sammlung oder Wie wird eine Viele-zu-Viele-Tabelle in eine Kriterienabfrage aufgenommen?

StackOverflow https://stackoverflow.com/questions/5392292

Frage

Ich bin ziemlich neu in der Welt von NHibernate und ich kann nicht scheinen, dass dies mit der Verwendung einer Kriterienabfrage funktioniert: Fragen Sie eine Viele-zu-Viele-Beziehung ab oder fragen Sie eine Sammlung (Set / Tasche) auf einer ab Entität. Ich habe im Internet gesucht und alle NHibernate-Bücher überprüft, aber ich kann keine spezifische Antwort auf meine "Herausforderung" finden.

Ich habe ein vereinfachtes Beispiel für das Problem gemacht, das ich zu lösen versuche. Ich habe einen Tisch mit Büchern, einen Tisch mit Kategorien und einen Viele-zu-Viele-Tisch mit den Kategorien pro Buch. Hier sind einige der technischen Details:

Datenstruktur:

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 # -Klassen:

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-Zuordnungen:

<?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>

Meine Frage: Ist es möglich, die Datenbank (unter Verwendung von Kriterien und / oder getrennten Kriterien) so abzufragen, dass ich die Bücher erhalte, die zu einer der von mir angegebenen Kategorien gehören (z. B. in catA oder catB) auch "und" sein)? Ich möchte dies in der Abfrage optimieren, nicht in C # (da ich alle Bücher aus der Datenbank lesen muss, bevor ich die Objekte basierend auf ihrer Sammlung von Tags filtern kann). Wenn ich die SQL von Hand schreiben würde, würde ich so etwas produzieren:

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

Da ich keine Entität für tableCategoriesPerBook habe, sehe ich keine Möglichkeit, mit einer Kriterienabfrage zu dieser Tabelle zu gelangen. Und ich möchte lieber keine handgeschriebenen SQL-Ausdrücke hinzufügen mit:

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

Ein letzter wichtiger Faktor: Ich verwende eine Brownfield-Datenbank, daher kann ich die Struktur nicht ändern! Damit muss ich datenbanktechnisch arbeiten.

War es hilfreich?

Lösung

Das ist ziemlich einfach.Sie können getrennte Kriterien verwenden.

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));

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top