He visto las preguntas similares, pero no puedo encontrar una explicación simple. Podría haberlo perdido, pero prometo que miré. En realidad, ni siquiera puedo encontrar la documentación que no sea una sola publicación de blog que pasa por alto todo rápidamente y supone que está familiarizado con otras formas de NH.NHibernate QueryOver Subconsulta
Dada una relación muchos-a-muchos entre Program
y Topic
, cuando éste se encuentra en una jerarquía de Topics
, quiero recuperar toda la Programs
para un determinado Topic
, posiblemente incluyendo sus subtemas. Como un programa puede enumerarse en múltiples subtemas de un tema principal dado, necesito usar una subconsulta o tratar con tener que usar distinct (y el enfoque simple de TransformUsing(Transformers.DistinctRootEntity)
no funcionó).
Raw SQL debe ser algo como
SELECT ProgramId, Title, bar, baz, foo FROM Programs
WHERE ProgramId IN
(SELECT ProgramId from Program_Topics WHERE TopicId IN (1, 2, ...))
Los resultados se echaron en un tipo de modelo para la transferencia a la vista. Mi primer intento fue la siguiente:
ProgramDTO pDTO = null;
/* topicIds is List<int> passed into function */
var query = Session.QueryOver<Program>()
.JoinQueryOver<Topic>(p => p.Topics)
.WhereRestrictionOn(pt => pt.Id).IsInG<int>(topicIds)
.TransformUsing(Transformers.DistinctRootEntity)
.SelectList(list => list
.Select(program => program.Id).WithAlias(() => pDTO.Id)
.Select(program => program.Title).WithAlias(() => pDTO.Title)
.Select(program => program.Location).WithAlias(() => pDTO.Location)
.Select(program => program.Description).WithAlias(() => pDTO.Description)
)
.TransformUsing(Transformers.AliasToBean(typeof(ProgramDTO)));
return query.List<ProgramDTO>();
Obviamente esto va en una unión en lugar de una subconsulta, pero no puedo encontrar un ejemplo de hacer una subconsulta con una relación muchos-a-muchos como este.
public class Program : Entity {
public virtual ISet<Topic> Topics { get; protected internal set; }
...
}
public class Topic : Entity {
public virtual ISet<Program> Programs { get; protected internal set; }
public virtual Topic ParentTopic { get; protected internal set; }
...
}
Esto realmente NO es la respuesta ya que Todavía creo la (s) unión (es) que quería evitar ... Elegí ir con una consulta HQL escrita a mano donde el problema se resuelve fácilmente. – Oliver
Si escribe a mano una consulta HQL, abandona el tipado fuerte y la refactorización, lo que es un gran beneficio para QueryOver. Si bien crea una JOIN adicional, espero que un optimizador de consultas SQL vea que no necesita la tabla adicional leyendo la cláusula JOIN y averiguando que puede seleccionar ese campo y obtener los mismos resultados. Si nada más, es probable que ejecute el WHERE primero y luego unirse en un índice, por lo que será rápido. –
Debo admitir que mi conocimiento de la ejecución del código SQL por SQL Server y sus posibles y probables optimizaciones es escaso, por lo que prefiero no confiar demasiado en él. Pero gracias por la información :-) – Oliver