2012-03-08 18 views
6

Obecnie mam następujący kod:Czy można refaktoryzować zapytanie 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 
    .... 
} 

Jak widać kwerenda jest taka sama za każdym razem, z wyjątkiem warunku publicationType. Próbowałem to zmienić, tworząc metodę, która zajmuje Func np.

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; 
} 

a następnie wywołanie tej metody jak

GetPublicationItems(IsBook); 

Ale kiedy to zrobić pojawia się błąd: InvalidCastException: Nie można rzutować obiektu typu „NHibernate.Hql.Ast.HqlParameter” wpisz "NHibernate.Hql.Ast.HqlBooleanExpression".

Czy jest inny sposób na zrobienie tego?

Odpowiedz

5

Brzmi to tak naprawdę nie potrzebują funkcji - po prostu potrzebują 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 
     { 
      ... 
     });     
} 

Jeśli naprawdę potrzebują go bardziej ogólne niż, to prawdopodobnie wystarczy zmienić swój kod użyć drzewa wyrażenie zamiast delegata (i zmienić typ wejścia):

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 
     { 
      ... 
     });     
} 

nie będzie w stanie wywołać go GetPublicationItems(IsBook) w tym momencie jednak. Można zrobić:

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

Lub:

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


... 

GetPublicationItems(IsBook) 
+0

Niesamowite dziękuję. Zrobiłem mój przykład trochę zbyt prosty i jak zauważyłeś mogę po prostu przekazać publicationType prosto do zapytania. Ale uogólnienie, które napisałeś po tym wydarzeniu, było dokładnie tym, o co prosiłem. – Zac

0

Czy istnieje powód, dla którego nie można po prostu użyć publicationType w zapytaniu?

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

Twój błąd był mylący Delegaci z drzewem Wyrażenie.

Func jest delegatem, którego nie można przekształcić w SQL. Mogłeś po prostu napisać go tak:

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

Albo, jeśli chcesz przekazać filtr, który sposób, jak pan wspomniał w próbce:

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