We have a filter string based on OData conventions
We need to parse this string, and execute a whereClause on our EntityFramework6 Model-First generated model.
Steps:
DbContext
to IEdmlModel
with Breeze EdmBuilder nuget package.ODataQueryContext
with this EdmModel
.FilterQueryOption
with the ODataQueryContext
and the filter string.At this moment, we have a FilterQueryOption
object with a well formed expression tree inside.
Our problem is when we convert this expression tree to Linq (used in the EF Where clause)
We found this method on Internet to make the conversion: (Exception message inside)
static private Expression<Func<Countries, bool>> GetFilterExpression(FilterQueryOption filter)
{
var enumerable = Enumerable.Empty<Countries>().AsQueryable();
var param = Expression.Parameter(typeof(Countries));
if (filter != null)
{
enumerable = (IQueryable<Countries>)filter.ApplyTo(enumerable, new ODataQuerySettings());
// Exception : The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type.
var mce = enumerable.Expression as MethodCallExpression;
if (mce != null)
{
var quote = mce.Arguments[1] as UnaryExpression;
if (quote != null)
{
return quote.Operand as Expression<Func<Countries, bool>>;
}
}
}
return Expression.Lambda<Func<Countries, bool>>(Expression.Constant(true), param);
}
Sample code (Solution + sql script to generate simple DB)
Could someone helps on this?
Like Chad Carisch said in comment, I need to use typeof(Countries)
to construct ODataQueryContext
.
After that the Exception thrown was "TestApiRest.Countries not found".
So I open the edmx file properties and changed the namespace to match my project namespace (It was TestApiRestModel, I change it to TestApiRest)
Here is my ODataFilterConverter
class that works with my first small test : odataString = "Id eq 2"
public class ODataFilterConverter
{
private readonly IEdmModel m_model;
public ODataFilterConverter(TestRestApiEntities db)
{
m_model = db.GetEdm(); // *Breeze Labs: EdmBuilder*
}
public Expression<Func<T, bool>> Convert<T>(string odataString)
{
var filterQueryOption = GetFilterQueryOption(GetQueryContext<T>(), odataString);
return GetFilterExpression<T>(filterQueryOption);
}
private ODataQueryContext GetQueryContext<T>()
{
return new ODataQueryContext(m_model, typeof(T));
}
private FilterQueryOption GetFilterQueryOption(ODataQueryContext queryContext, string filter)
{
return new FilterQueryOption(filter, queryContext);
}
static private Expression<Func<T, bool>> GetFilterExpression<T>(FilterQueryOption filter)
{
var enumerable = Enumerable.Empty<T>().AsQueryable();
var param = Expression.Parameter(typeof(T));
if (filter != null)
{
enumerable = (IQueryable<T>)filter.ApplyTo(enumerable, new ODataQuerySettings());
var mce = enumerable.Expression as MethodCallExpression;
if (mce != null)
{
var quote = mce.Arguments[1] as UnaryExpression;
if (quote != null)
{
return quote.Operand as Expression<Func<T, bool>>;
}
}
}
return Expression.Lambda<Func<T, bool>>(Expression.Constant(true), param);
}
}