2010-02-13 9 views
1

Je n'arrive pas à faire en sorte que NHibernate génère une requête SQL qui s'exécute réellement sans erreur, car il manque des jointures pour mes sous-classes.Comment générer des jointures de sous-classes dans une SqlQuery NHibernate?

permet de prendre cet exemple minimal:

class Page 
{ 
    public virtual int Id { get; set; } 
    public virtual string UrlSegment { get; set;} 
    public virtual Page Parent { get; set; } 
} 

class ContentPage 
{ 
    public string Content { get; set; } 
} 

Maintenant, imaginez un champ pour champ direct, la cartographie rejoint sous-classe de ce à la base de données. Je suis venu avec cette requête pour trouver toutes les pages le long du chemin/page/page2/page3:

SELECT p1.* FROM page p1 
WHERE 
    p1.parent IS NULL 
    AND p1.hierarchysegment = 'test' 

UNION 

SELECT p2.* FROM page p1 
JOIN page p2 ON p2.parent = p1.id 
WHERE 
    p1.parent IS NULL 
    AND p1.hierarchysegment = 'test' 
    AND p2.hierarchysegment = 'test2' 

UNION 

SELECT p3.* FROM page p1 
JOIN page p2 ON p2.parent = p1.id 
JOIN page p3 ON p3.parent = p2.id 
WHERE 
    p1.parent IS NULL 
    AND p1.hierarchysegment = 'test' 
    AND p2.hierarchysegment = 'test2' 
    AND p3.hierarchysegment = 'test3' 
; 

Maintenant, cela semble fonctionner ok lors de l'exécution de la requête. Permet d'essayer de générer cela avec un sqlquery (simplifié, montre seulement la première partie):

IQuery q = session.CreteSQLQuery("SELECT {p0.*} FROM page {p0} WHERE {p0.Parent} IS NULL" + 
           "AND {p0.HierarchySegment} = 'page1'", "p0", typeof(Page)); 

Cela génère la requête suivante:

SELECT p0.ID   AS id0_0_, 
    p0.enabled   AS enabled0_0_, 
    p0.linktext   AS linktext0_0_, 
    p0.hierarchysegment AS hierarch4_0_0_, 
    p0.tooltiptext  AS tooltipt5_0_0_, 
    p0.PARENT   AS parent0_0_, 
    p0_1_.content  AS content1_0_, 
    CASE 
     WHEN p0_1_.ID IS NOT NULL 
     THEN 1 
     WHEN p0.ID IS NOT NULL 
     THEN 0 
    END AS clazz_0_ 
FROM page p0 
WHERE parent0_0_ IS NULL 
    AND hierarch4_0_0_ = page1; 

Mais cette requête contient des erreurs SQL car NHibernate essaie de récupérer les champs qui sont seulement disponibles après que NHibernate a ajouté des jointures pour la sous-classe, ContentPage. Est-il possible d'ajouter en quelque sorte ces jointures sans s'appuyer sur un style de nommage spécifique que NHibernate utilise (c'est-à-dire, générer les jointures nécessaires manuellement)?

Répondre

0

Vous pouvez vous rapprocher avec une requête HQL. Comme il n'y a pas d'UNION dans HQL, j'utilise MultiQuery. De plus, la sous-classe jointe signifie que chacune des requêtes aura une jointure LEFt JOIN sur la table de la page de contenu.

var q1 = session.CreateQuery(@" 
    from Page p1 
    where p1.Parent is null 
    and  p1.UrlSegment=:s1"); 

var q2 = session.CreateQuery(@" 
    select p2 
    from Page p2 inner join p2.Parent p1 
    where p1.Parent is null 
    and  p1.UrlSegment=:s1 
    and  p2.UrlSegment=:s2"); 

var q3 = session.CreateQuery(@" 
    select p3 
    from Page p3 inner join p3.Parent p2 
      inner join p2.Parent p1 
    where p1.Parent is null 
    and  p1.UrlSegment=:s1 
    and  p2.UrlSegment=:s2 
    and  p3.UrlSegment=:s3"); 

var results = session.CreateMultiQuery() 
    .Add<Page>(q1) 
    .Add<Page>(q2) 
    .Add<Page>(q3) 
    .SetParameter("s1", "test1") 
    .SetParameter("s2", "test2") 
    .SetParameter("s3", "test3") 
    .List(); 

var l1 = (IList<Page>) results[0]; 
var l2 = (IList<Page>) results[1]; 
var l3 = (IList<Page>) results[2]; 

if (l1.Count != 0) p1 = l1[0]; 
if (l2.Count != 0) p2 = l2[0]; 
if (l3.Count != 0) p3 = l3[0]; 
+0

En effet, ce serait une solution. Ce n'est pas une solution générale au problème de générer les jointures pour le SQL, donc je vais attendre encore plus avant d'accepter cela comme réponse. –