Restrictions.On(_func) - Variable 'p' of type 'Product' referenced from scope'', but it is not defined on passthrough

StackOverflow https://stackoverflow.com/questions/19235991

Domanda

I've been unable to get this generic nhibernate query to work as I keep getting:

Variable 'p' of type 'Product' referenced from scope'', but it is not defined

I've fiddled around with a large number of different answers to this question, and I think I understand what the issue is, I'm just not sure how to solve it. As far as I understand, 'p' exists in the original scope, but stops existing by the time it gets down to the nhibernate queryover command, so since Linq references objects by name it doesn't actually know what I'm talking about anymore.

I tried various methods included in: variable 'x' of type 'Product' referenced from scope, but it is not defined; NHibernate : QueryOver in generic method; Generic Repository with nHibernate; LambdaExpression Variable Referenced From Scope But Not Defined; LINQ expressions. Variable 'p' of type referenced from scope, but it is not defined

Unfortunately none of these provided an answer that was able to solve the issue. The Query:

public class ProductsInformationQuery<T>: Query<T> where T:Product
{
    private readonly List<string> _ids;
    private readonly Expression<Func<T, object>> _func;

    public ProductsInformationQuery(List<string> ids, 
        FeaturedIdType featureIdType, Expression<System.Func<T,object>> func)
    {
        _ids = ids;
        _func = func;
    }

    public override List<T> Execute()
    {
        return Session.QueryOver<T>().Where(Restrictions.On<T>(_func).IsIn(_ids.Select(i => i).ToList())).List().ToList();
    }
}

This takes in a list of strings and checks the database for a specific query. This will allow us to try and check the database for a group of Ids; the Ids can be either Guids(such as an Id) or Strings (such as a Name).

The calling code:

private List<Product> LoadProducts(List<string> ids)
    {
        System.Linq.Expressions.Expression<Func<Product, object>> function = b => b.Id.ToString();
        return _productsRepository.Execute(new ProductsInformationQuery<Product>(ids, FeaturedIdType.ProductId,function)).ToList();
    }

This code needs to be able to send 'b=> b.Id.ToString()' in as the function that it needs to check on. The QueryOver command would then need to find the Product by its Id. Product is the top level of a inheritance chain, so I want to be able to find various types of products by various types of information from the database.

Interestingly I could get the following to work:

return Session.QueryOver<T>().Where(Restrictions.On<T>(b=>b.Id).IsIn(_ids.Select(Guid.Parse).ToList())).List().ToList();

But not the following two:

return Session.QueryOver<T>().Where(Restrictions.On<T>(b=>b.Id).IsIn(_ids)).List().ToList();

((AOD Exception))

return Session.QueryOver<T>().Where(Restrictions.On<T>(b=>b.Id.ToString()).IsIn(_ids)).List().ToList();

((Above error; "variable 'b' of type..."))

The former is a Guid to Guid comparison, the Second a Guid to String (not surprised that Guid to string doesn't work with nhibernate) and the third was Guid into String to string, which would be changing b instead of just collecting data.

Is there any way to let this take strings and Guids and ints and any other data type, while still being able to take in any kind of product? Or am I limited to making several versions of the query?

Thanks!

È stato utile?

Soluzione

I would add a generic type parameter, TIdType to your class that represents the type of the Id you'd like to use. This would end up looking something like this:

public class ProductsInformationQuery<TResultType, TIdType>: Query<TResultType> 
    where TResultType : Product
{
    private readonly List<TIdType> _ids;
    private readonly Expression<Func<TResultType, object>> _func;

    public ProductsInformationQuery(
        List<TIdType> ids, 
        FeaturedIdType featureIdType, 
        Expression<System.Func<TResultType, TIdType>> func)
    {
        _ids = ids;

        System.Linq.Expressions.Expression converted = 
            System.Linq.Expressions.Expression.Convert(func.Body, typeof(object));

        _func = System.Linq.Expressions.Expression.Lambda<Func<TResultType, object>>
           (converted, func.Parameters);
    }

    public override List<TResultType> Execute()
    {
        return Session.QueryOver<TResultType>()
            .Where(Restrictions.On<TResultType>(_func)
                .IsIn(_ids.ToArray())
            .List()
            .ToList();
    }
}

I took the code to convert the Expression<Func<TResultType, TIdType>> to Expression<Func<TResultType, object>> from this answer.

Your calling code would look like this:

private List<Product> LoadProducts(List<string> ids)
{
    System.Linq.Expressions.Expression<Func<Product, Guid>> function = b => b.Id;
    return _productsRepository.Execute(
        new ProductsInformationQuery<Product, Guid>
           (ids, FeaturedIdType.ProductId, function))
       .ToList();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top