2012-03-08 12 views
6

Actualmente tengo el siguiente código:¿Es posible refactorizar esta consulta de nHibernate Linq?

switch (publicationType) 
{ 
    case PublicationType.Book: 
     return Session.Query<Publication>() 
      .Where(p => p.PublicationType == PublicationType.Book) 
      .OrderByDescending(p => p.DateApproved)       
      .Take(10) 
      .Select(p => new PublicationViewModel 
      { 
       ... 
      }); 
    case PublicationType.Magazine: 
     return Session.Query<Publication>() 
      .Where(p => p.PublicationType == PublicationType.Magazine) 
      .OrderByDescending(p => p.DateApproved)       
      .Take(10) 
      .Select(p => new PublicationViewModel 
      { 
       ... 
      }); 
    case PublicationType.Newspaper 
    .... 
} 

Como se puede ver la consulta es el mismo cada vez con excepción de la condición publicationType. Traté de refactorizar esto creando un método que tenga una Func, p.

private IEnumerable<PublicationViewModel> GetPublicationItems(Func<PublicationType, bool>> pubQuery) 
{ 
    return Session.Query<Publication>() 
     .Where(pubQuery)     
     .OrderByDescending(p => p.DateApproved)       
     .Take(10) 
     .Select(p => new PublicationViewModel 
     { 
      ... 
     });     
} 

private bool IsBook(PublicationType publicationType) 
{ 
    return publicationType == PublicationType.Book; 
} 

y luego llamar a este método como

GetPublicationItems(IsBook); 

Pero cuando hago esto me sale el error: InvalidCastException: No se puede convertir objeto de tipo 'NHibernate.Hql.Ast.HqlParameter' para escribir 'NHibernate.Hql.Ast.HqlBooleanExpression'.

¿Hay alguna otra manera de hacerlo?

Respuesta

5

Parece que usted no necesita realmente una función - sólo tiene un PublicationType:

private IEnumerable<PublicationViewModel> 
    GetPublicationItems(PublicationType type) 
{ 
    return Session.Query<Publication>() 
     .Where(p => p.PublicationType == type) 
     .OrderByDescending(p => p.DateApproved)       
     .Take(10) 
     .Select(p => new PublicationViewModel 
     { 
      ... 
     });     
} 

Si realmente necesita es más general que eso, es probable que sólo tenga que cambiar su código para utilizar un árbol de expresión en lugar de un delegado (y cambiar el tipo de entrada):

private IEnumerable<PublicationViewModel> GetPublicationItems(
    Expression<Func<Publication, bool>> pubQuery) 
{ 
    return Session.Query<Publication>() 
     .Where(pubQuery)     
     .OrderByDescending(p => p.DateApproved)       
     .Take(10) 
     .Select(p => new PublicationViewModel 
     { 
      ... 
     });     
} 

usted no será capaz de llamar con GetPublicationItems(IsBook) en ese punto, sin embargo. Usted podría hacer:

GetPublicationItems(p => p.PublicationType == PublicationType.Book) 

O:

private static readonly Expression<Func<Publication, bool>> IsBook = 
    p => p.PublicationType == PublicationType.Book; 


... 

GetPublicationItems(IsBook) 
+0

impresionante gracias. Hice mi ejemplo un poco demasiado simple y como usted señaló, podría pasar el tipo de publicación directamente a la consulta. Pero la generalización que publicaste después de eso era exactamente lo que buscaba. – Zac

0

¿Hay alguna razón no se puede simplemente usar publicationType en la consulta?

return Session.Query<Publication>() 
     .Where(p => p.PublicationType == publicationType) 
     .OrderByDescending(p => p.DateApproved)       
     .Take(10) 
     .Select(p => new PublicationViewModel 
     { 
      ... 
     }); 
0

Tu error ha sido un error Delegados con Expression trees.

Func es un delegado, que no se puede convertir en SQL. Sólo podría haber escrito así:

Session.Query<Publication>() 
.Where(p => p.PublicationType == yourPubilcationType) 
... 

O, si desea pasar un filtro de ese método, como se insinuó en su muestra:

IEnumerable<PublicationViewModel> GetPublicationItems(Expression<Func<PublicationType, bool>> pubQuery) 
{ 
    return Session.Query<Publication>() 
     .Where(pubQuery)     
     .OrderByDescending(p => p.DateApproved)       
     .Take(10) 
     .Select(p => new PublicationViewModel 
     { 
      ... 
     });     
} 
Cuestiones relacionadas