c# - 从 FilterQueryOption 获取 Linq 表达式抛出 CLR 异常

标签 c# linq odata entity-framework-6 linq-expressions

我们有一个基于 OData conventions 的过滤器字符串

我们需要解析这个字符串,并在我们的 EntityFramework6 Model-First 生成的模型上执行 whereClause。

步骤:

  1. 使用 Breeze EdmBuilder nuget 包将我们的 DataModel DbContext 转换为 IEdmlModel
  2. 使用此 EdmModel 创建一个 ODataQueryContext
  3. 使用 ODataQueryContext 和过滤器字符串创建一个 FilterQueryOption

此时,我们有一个 FilterQueryOption 对象,里面有一个格式正确的表达式树。

我们的问题是当我们将这个表达式树转换为 Linq(在 EF Where 子句中使用)

我们在网上找到了这个方法来进行转换: (里面有异常信息)

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)

有人可以帮忙吗?

最佳答案

Chad Carisch在评论中说,我需要使用typeof(Countries) 来构造ODataQueryContext

在那之后抛出的异常是“TestApiRest.Countries not found”。

所以我打开 edmx 文件属性并更改命名空间以匹配我的项目命名空间 (原来是TestApiRestModel,我改成了TestApiRest)

这是我的 ODataFilterConverter 类,它适用于我的第一个小测试: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);
    }
  }

关于c# - 从 FilterQueryOption 获取 Linq 表达式抛出 CLR 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25668344/

相关文章:

c# - LINQ 连接两个表

c# - 如何使用 LINQ 组记录和使用 Distinct

c# - 如何在C#中向linq select new命令的结果中添加项目?

c# - 如何将 OData 与 ASP.net Core 正确集成

odata - OData 元数据中 <FunctionImport> 的含义是什么?

c# - 在 web.config 中指定链接的 sql server

c# - Task.Yield、Task.Run 和 ConfigureAwait(false) 之间有什么区别?

c# - 执行我的 javascript 后页面重新加载,我不希望它这样做

c# - 将查询字符串值绑定(bind)到字典

c# - 如何使用来自不同项目的模型类通过反射提供程序创建 WCF 数据服务 OData?