2011-08-22 12 views
9

He estado buscando durante varias horas cómo hacer esto, pero parece que no puedo encontrar nada que me ayude.nhibernate queryover join with subquery para obtener la columna agregada

Aquí es el modelo de base de datos:

enter image description here

Ésta es la consulta SQL que estoy tratando de ejecutar:

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 

Así que, básicamente, quiero devolver una lista de ramas y una nueva columna que representa el número de asignaciones para esa rama.

modelo de oficina

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

    public virtual string Name { get; set; } 

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

} 

modelo AssignmentBranch

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

    public virtual DateTime AssignedOn { get; set; } 

    public virtual Branch Branch { get; set; } 
} 

Aquí está mi configuración de 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" /> 

He intentado esto de varias maneras, pero parece que no puedo encontrar la forma de unirme a una subconsulta con QueryOver.

Traté de esta manera:

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

Puede alguien ayudarme por favor? No tiene que ser con un sub-unirse con exactitud, tal vez hay otra solución mejor por ahí que me falta ...

Gracias, Cosmin

Respuesta

12

Después de leer cientos de preguntas similares en aquí , He encontrado la respuesta: una subconsulta correlacionada. De esta manera:

// 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 pregunta similar que tengo mi respuesta es de this one.

+0

bonito. Pensé que necesitabas todo el objeto Branch y no solo algunas propiedades. – Firo

+0

Lo necesito para completar una entidad personalizada con algunas propiedades de rama y el recuento de las asignaciones. Sin embargo, gracias por tomarse el tiempo para responder, creo que su respuesta también es interesante. – noir

+0

Esto crea una subconsulta anidada en lugar de una combinación de la izquierda. Esperaría que esto funcione mucho peor que una unión (aunque el optimizador de consultas SQL me sorprende continuamente :-) –

2

no es tan fácil con QueryOver, porque actualmente no es posible tener declaraciones en la cláusula FROM. Una cosa que viene a la mente (no de la manera más eficiente creo)

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 sería

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