2011-08-22 13 views
9

Ho cercato per parecchie ore ora come farlo, ma non riesco a trovare nulla che possa aiutarmi.nhibernate queryover join con subquery per ottenere la colonna aggregata

Ecco il modello di database:

enter image description here

Questa è la query SQL che sto cercando di eseguire:

SELECT b.*, a.Assignments FROM Branch b LEFT JOIN (
     SELECT b.BranchID , COUNT(ab.BranchID) AS Assignments 
     FROM Branch b LEFT JOIN AssignmentBranch ab ON b.BranchID = ab.BranchID 
     GROUP BY b.BranchID 
    ) a ON b.BranchID = a.BranchID 

Quindi, in sostanza, voglio restituire un elenco di filiali e una nuova colonna che rappresenta il numero di assegnazioni per quel ramo.

modello di filiale

public class Branch : IEntity<int> 
{ 
    public virtual int ID 
    { 
     get; 
     set; 
    } 

    public virtual string Name { get; set; } 

    public virtual IList<AssignmentBranch> Assignments { get; set; } 

} 

modello AssignmentBranch

public class AssignmentBranch : IEntity<int> 
{ 
    public virtual int ID 
    { 
     get; 
     set; 
    } 

    public virtual DateTime AssignedOn { get; set; } 

    public virtual Branch Branch { get; set; } 
} 

Qui è la mia configurazione di NHibernate:

<class name="Branch" table="Branch"> 

<id name="ID" column="BranchID"> 
    <generator class="identity"></generator> 
</id> 

<property name="Name"/> 

<bag name="Assignments" cascade="none" inverse="true"> 
    <key column="BranchID"/> 
    <one-to-many class="AssignmentBranch"/> 
</bag> 

<class name="AssignmentBranch" table="AssignmentBranch"> 

<id name="ID" column="AssignmentBranchID"> 
    <generator class="identity"></generator> 
</id> 

<property name="AssignedOn" /> 
<property name="FromDate" /> 
<property name="ToDate" /> 

<many-to-one name="Assignment" column="AssignmentID" /> 
<many-to-one name="Branch" column="BranchID" /> 

Ho provato questo un certo numero di modi, ma non riesco a trovare un modo per unire con una sottoquery utilizzando QueryOver.

ho provato in questo modo:

// aliases 
Branch branch = null; AssignmentBranch assignment = null; 

var subquery = QueryOver.Of<Branch>(() => branch) 
    .Where(() => branch.Project.ID == projectID) 
    .JoinQueryOver<AssignmentBranch>(() => branch.Assignments,()=> assignment, 
            NHibernate.SqlCommand.JoinType.LeftOuterJoin) 
    .SelectList(list => list 
         .SelectGroup(x=>x.ID) 
         .SelectCount(()=>assignment.ID) 
        ); 

    var query = session.QueryOver<Branch>(()=>branch) 
        .JoinAlias(???) // how can I join with a sub-query? 
        .TransformUsing(Transformers.AliasToBean<BranchAssignments>()) 
        .List<BranchAssignments>(); 

Qualcuno mi può aiutare per favore? Esso non deve essere con un sub-join esattamente, forse c'è un'altra soluzione migliore là fuori che mi manca ...

Grazie, Cosmin

risposta

12

Dopo aver letto centinaia di domande simili qui , Ho trovato la risposta: una sotto-query correlata. Come questo:

// aliases 
Branch branch = null; AssignmentBranch assignment = null; 

var subquery = QueryOver.Of<AssignmentBranch>(() => assignment) 
    .Where(() => assignment.Branch.ID == branch.ID) 
    .ToRowCountQuery(); 

var query = session.QueryOver<Branch>(() => branch) 
    .Where(() => branch.Project.ID == projectID) 
    .SelectList 
    (
     list => list 
     .Select(b => b.ID) 
     .Select(b => b.Name) 
     .SelectSubQuery(subquery) 
    ) 
    .TransformUsing(Transformers.AliasToBean<BranchAssignments>()) 
    .List<BranchAssignments>(); 

La domanda simile ho avuto la mia risposta da è this one.

+0

bello. Pensavo avessi bisogno dell'intero oggetto Branch e non solo di alcune proprietà. – Firo

+0

Mi serve per popolare un'entità personalizzata con alcune proprietà del ramo e il conteggio dei compiti. Tuttavia, grazie per aver trovato il tempo di rispondere, penso che anche la tua risposta sia interessante. – noir

+0

Questo crea una sottoquery nidificata piuttosto che un'unione di sinistra. Mi aspetto che questo funzioni molto di peggio di un join (anche se SQL Query Optimizer mi sorprende continuamente :-) –

2

non è così facile con QueryOver, perché al momento non è possibile avere istruzioni nella clausola FROM. Una cosa che mi viene in mente (non è il modo più efficace credo)

var branches = session.QueryOver<Branch>().Future(); 

var assignmentMap = session.QueryOver<BranchAssignment>() 
    .Select(
     Projections.Group<BranchAssignment>(ab => ab.Branch.Id).As("UserId"), 
     Projections.RowCount()) 
    .Future<object[]>() 
    .ToDictionary(o => (int)o[0], o => (int)o[1]); 

return branches.Select(b => new { Branch = branch, AssignmentCount = assignmentMap[branch.Id] }); 

con LINQ sarebbe davvero

var branchesWithAssignementCount = session.Query<Branch>() 
    .Select(b => new { Branch = b, AssignmentCount = b.Branch.Count }) 
    .ToList(); 
Problemi correlati