2009-05-13 7 views
2

J'ai une requête SQL que je dois représenter en utilisant l'API ICriteria de NHibernate.NHibernate - rejoindre une sous-requête en utilisant ICriteria

SELECT u.Id as Id, 
    u.Login as Login, 
    u.FirstName as FirstName, 
    u.LastName as LastName, 
    gm.UserGroupId_FK as UserGroupId, 
    inner.Data1, 
    inner.Data2, 
    inner.Data3 
    FROM dbo.User u inner join 
    dbo.GroupMember gm on u.Id = gm.UserAnchorId_FK 
    left join 
    (
     SELECT 
     di.UserAnchorId_FK, 
     sum(di.Data1) as Data1, 
     sum(di.Data2) as Data2, 
     sum(di.Data3) as Data3 
     FROM 
     dbo.DailyInfo di 
     WHERE di.Date between '2009-04-01' and '2009-06-01' 
     GROUP BY di.UserAnchorId_FK 
    ) inner ON inner.UserAnchorId_FK = u.Id 
    WHERE gm.UserGroupId_FK = 195 

tentatives jusqu'à présent ont inclus la cartographie « utilisateur » et des classes « DailyInfo » (mes entités) et de faire un objet DailyInfo une propriété de l'objet utilisateur. Cependant, comment cartographier la relation de clé étrangère est encore un mystère, à savoir

<one-to-one></one-to-one> 

<one-to-many></one-to-many> 

<generator class="foreign"><param name="property">Id</param></generator> (!) 

Solutions sur le Web sont généralement à faire avec les sous-requêtes dans une clause WHERE, mais je dois gauche se joindre à cette sous-requête au lieu de Assurez-vous que les valeurs NULL sont renvoyées pour les lignes qui ne sont pas jointes.

J'ai le sentiment que je devrais utiliser un critère pour la requête externe, puis former une 'jointure' avec un DetachedCriteria pour représenter la sous-requête?

Répondre

0

En ce qui concerne la cartographie des relations, il semble que vous avez un à plusieurs entre l'utilisateur et DailyInfo:

<!-- User mapping --> 
<bag name="DailyInfos" inverse="true"> 
    <key column="UserAnchorId_FK" /> 
    <one-to-many class="Namespace.To.DailyInfo, Namespace" /> 
</bag> 

<!-- DailyInfo mapping --> 
<many-to-one name="User" column="UserAnchorId_FK" /> 

Pour le reste, je ne suis pas tout à fait sûr pour le moment. .. il semble que vous pouvez avoir un many-to-many entre User et Group via le tableau GroupMember, ce qui peut être un facteur de complication. Gardez à l'esprit que vous pouvez faire .CreateCriteria("Association path", jointype) sur un critère pour créer un sous-critère avec le type de jointure spécifié. Publier un aperçu de vos relations classe/table pourrait vous aider.

1

Même problème que je rencontre et je n'a pas obtenu solutions.So je l'ai fait un hack avec intercepteurs

requête générée par critères

SELECT u.Id as Id, 
u.Login as Login, 
u.FirstName as FirstName, 
u.LastName as LastName, 
gm.UserGroupId_FK as UserGroupId, 
inner.Data1, 
inner.Data2, 
inner.Data3 
FROM dbo.User u inner join 
dbo.GroupMember gm on u.Id = gm.UserAnchorId_FK 
InnerJoin inner ON inner.UserAnchorId_FK = u.Id 
WHERE gm.UserGroupId_FK = 195 

Ici InnerJoin est une table factice qui a 1-1 relation avec l'utilisateur. Colonnes dans InnerJoin sont des valeurs retour de jointure interne sous requête

Critères pour l'utilisateur et InnerJoin

DetachedCriteria forUser = DetachedCriteria.For<User>(); 
forUser.CreateCriteria("InnerJoin"); 

Maintenant, vous pouvez faire intercepteur pour modifier la requête

public interface CustomInterceptor : IInterceptor, EmptyInterceptor 
{  
SqlString IInterceptor.OnPrepareStatement(SqlString sql) 
{ 
    string query = sql.ToString(); 
    if (query.Contains("InnerJoin ")) 
    { 
     sql = sql.Replace("InnerJoin ", "(select [vals] form dbo.DailyInfo [where conditions])"); 
    } 
    return sql; 
} 
} 

Pour les valeurs de retour à partir de plusieurs tables y compris sous-requête jointe, vous pouvez avoir besoin d'utiliser NHibernate DTO Et la session est comme ça

CustomInterceptor custonInterceptor=new CustomInterceptor(); 

sessionFactory.OpenSession(custonInterceptor); 

Et la requête finale sera comme exactement ce que vous voulez obtenir