Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to refactor this nHibernate Linq query?

Currently I have the following code:

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

As you can see the query is the same each time except for the publicationType condition. I tried to refactor this by creating a method that takes a Func e.g.

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

and then calling this method like

GetPublicationItems(IsBook);

But when I do this I get the error: InvalidCastException: Unable to cast object of type 'NHibernate.Hql.Ast.HqlParameter' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'.

Is there another way to do this?

like image 672
Zac Avatar asked Mar 08 '12 19:03

Zac


1 Answers

It sounds like you don't really need a function - you just need a 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
        {
            ...
        });                
}

If you really need it more general than that, you probably just need to change your code to use an expression tree instead of a delegate (and change the input type):

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

You won't be able to call it with GetPublicationItems(IsBook) at that point though. You could do:

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

Or:

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


...

GetPublicationItems(IsBook)
like image 123
Jon Skeet Avatar answered Oct 14 '22 17:10

Jon Skeet