Consulta sobre referencia HasMany

Resuelto dhrm asked hace 10 años • 2 respuestas

Tengo un modelo de entidad como este:

public class Request
{
    public virtual IList<Response> Responses { get; set; }
}

public class Response
{
    public virtual DateTime Timestamp { get; set; }
    public virtual bool Success { get; set; }
}

Estoy intentando crear una consulta que me proporcione todas las solicitudes en las que su última respuesta (con respecto a su marca de tiempo ) sea exitosa . ¿Cómo se puede hacer esto?

dhrm avatar Dec 12 '13 02:12 dhrm
Aceptado

Como casi siempre, NHibernate tiene la respuesta para esto. Lo que estamos tratando de lograr aquí sería una declaración SQL similar a esta:

// final Request selection
SELECT request.[RequestId] 
 FROM [Request] request 

   // Only requests, which are successful, and have Max(date)
   WHERE request.[RequestId] IN 
   (
     SELECT successResponse.RequestId as y0_ 
      FROM [Response] successResponse 

        // response which max date is equal to the upper response
        // and which RequestId corresponds with supper upper Request
        WHERE EXISTS
        (
          SELECT maxResponse.RequestId as y0_
           , max(maxResponse.[DateTime]) as y1_           
           FROM [Response] maxResponse 

           // do the MAX only for current Request
           WHERE maxResponse.RequestId = successResponse.RequestId 
           GROUP BY maxResponse.RequestId 

           // assure that the Response match is on the max DateTime
           HAVING max(maxResponse.[DateTime]) = successResponse.[DateTime]
        ) 
        AND successResponse.[Success] = 1
   )

Notas:

  1. Esperar la respuesta tiene RequestId
  2. arriba se usó el comentario C# //en lugar de SQL--

Y ahora la magia de NHibernate y QueryOver:

// This declaration will allow us, to use a reference from middle SELECT
// in the most deeper SELECT
Response response = null;

// the most INNER SELECT
var maxSubquery = QueryOver.Of<Response>()
   .SelectList(l => l
    .SelectGroup(item => item.RequestId)
    .SelectMax(item => item.DateTime)
    )
    // WHERE Clause
   .Where(item => item.RequestId == response.RequestId)
   // HAVING Clause
   .Where(Restrictions.EqProperty(
      Projections.Max<Response>(item => item.DateTime),
      Projections.Property(() => response.DateTime)
    ));

// the middle SELECT
var successSubquery = QueryOver.Of<Response>(() => response)
    // to filter the Request
    .Select(res => res.RequestId)
    .WithSubquery
    .WhereExists(maxSubquery)
    // now only these wich are successful
    .Where(success => success.Success == true)
    ;

En este momento tenemos SUB SELECT internos, anidados. usémoslos:

// the most outer SELECT
var query = session.QueryOver<Request>();
query.WithSubquery
    // our Request ID is IN(...
    .WhereProperty(r => r.ID)
    .In(successSubquery);

var list = query
    .List<Request>();

Notas finales, no estoy discutiendo el concepto. No la actuación. Preferiría usar una configuración en la respuesta "IsActive" y hacerlo más fácil ... esta es solo la respuesta sobre cómo hacerlo...

Radim Köhler avatar Dec 12 '2013 07:12 Radim Köhler