How to get a method to return an expression to res

2019-07-29 06:25发布

I have the following statement that's throwing an error I don't understand:

return (int) _session.CreateCriteria<T>()
    .Add(LambdaSubquery.Property<Fund>(x => x.Id)
        .In(GetAvailableIdsPerDataUniverse(x => x.GetDataUniverseId())))
    .AddNameSearchCriteria<T>(searchExpression)
    .SetProjection(LambdaProjection.Count<T>(e => e.Id))
    .UniqueResult();

This is the error:

Unrecognised method call in epression x.GetDataUniverseId()

Background:

I have some different types that I need to perform searches for. Each of these types implement ISearchable which requires that they have Name & Id properties as well as the GetDataUniverseId() method, which will return an expression representing the dataUniverseId needed for the LambdaProjection.

The method GetAvailableIdsPerDataUniverse(x => x.GetDataUniverseId()) has the following signature:

protected DetachedCriteria 
GetAvailableIdsPerDataUniverse(System.Linq.Expressions.Expression<Func<Fund, object>> dataUniverseId)

and x => x.GetDataUniverseId() is defined in my Fund class as

public virtual System.Linq.Expressions.Expression<Func<Fund, object>> GetDataUniverseId()
{
    return f => f.Id;
}

and for example as the following in the Company class:

public virtual Expression<Func<Fund, object>> GetDataUniverseId()
{
    return f => f.Company.Id;
}

This works if instead of trying to pass x => x.GetDataUniverseId() as the parameter, I 'hard-code' f => f.Id or f => f.Company.Id. I'd like it if the type being worked on was able to supply the expression it needed rather than me having to pass that expression into every method that uses GetAvailableIdsPerDataUniverse(). I thought that instead of accessing a property on the inferred type, it could execute a method that would return the expression.

Question:

Is there anything I can do to resolve this error?

Note:

Everything builds fine, so I was a little surprised to see that it threw an error when I ran it. Mostly because when I passed in the expression as a parameter that I 'hard-coded' it worked fine.

Also, I've also tried the following to no avail, where I specify the type I want GetAvailableIdsPerDataUniverse to act on:

.In(GetAvailableIdsPerDataUniverse<Fund>(x => x.GetDataUniverseId())))

2条回答
Melony?
2楼-- · 2019-07-29 07:08

I've been informed that the problem here is that I want the behaviour of polymorphic static methods, but I can't have that because GetDataUniverseId is not an instance method, and I need an instance to be able to use it polymorphically.

The solution, although inefficient because it uses lots of reflection is to use new T()

such that

    .Add(LambdaSubquery.Property<Fund>(x => x.Id)
        .In(GetAvailableIdsPerDataUniverse(x => x.GetDataUniverseId())))

becomes

    .Add(LambdaSubquery.Property<Fund>(x => x.Id)
        .In(GetAvailableIdsPerDataUniverse((new T()).GetDataUniverseId())))

The only other issue with this is that the method this exists inside:

    public IEnumerable<T> GetEntitiesByName<T>(int pageSize, string searchExpression)
        where T : class, ISearchableEntity

must now have the new() constraint, as follows:

    public IEnumerable<T> GetEntitiesByName<T>(int pageSize, string searchExpression) 
        where T : class, ISearchableEntity, new()

I hope somebody finds more use from this than the 'answer' provided by @Sunny

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-07-29 07:14

Try:

return (int) _session.CreateCriteria<T>()
    .Add(LambdaSubquery.Property<Fund>(x => x.Id)
        .In(GetAvailableIdsPerDataUniverse(y => y.GetDataUniverseId())))
    .AddNameSearchCriteria<T>(searchExpression)
    .SetProjection(LambdaProjection.Count<T>(e => e.Id))
    .UniqueResult();
查看更多
登录 后发表回答