.NET Core 3 InvalidOperationException on OrderBy 与动态字段名称

eri*_*pap 3 c# linq entity-framework-core ef-core-3.0

我正在从 .NET Core 2 o 3 版本迁移现有的 Web API。经过几个问题,我设法使它工作,除了按列名的 Dynamic OrderBy。

这是我的代码,与 .net core 2 配合使用效果很好:

public async Task<IEnumerable<Clientes_view>> GetClientes(int bActivos, int nRegistroInic, int nRegistros, string sOrdenar, 
        int nSentido, string sFiltro, int nTipo = -1, int idCliente = -1)
    {
        var clientes = this.context.Set<Clientes_view>()
           .Where(e => e.RazonFantasia.Contains(sFiltro) || e.RazonFantasia.Contains(sFiltro)
               || e.Cuit.Contains(sFiltro) || e.Mail.StartsWith(sFiltro) || string.IsNullOrEmpty(sFiltro))
           .Where(e => (e.Activo && bActivos == 1) || bActivos == -1 || (!e.Activo && bActivos == 0))
           .Where(e => e.IdTipoCliente == nTipo || nTipo == -1)
           .Where(e => e.IdCliente == idCliente || idCliente == -1);

        if (!string.IsNullOrEmpty(sOrdenar))
        {
            var propertyInfo = this.context.Set<Clientes_view>().First().GetType().GetProperty(sOrdenar, 
                BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

            if (propertyInfo != null) if (nSentido == -1) clientes = clientes.OrderByDescending(e => propertyInfo.GetValue(e, null));
                else clientes = clientes.OrderBy(e => propertyInfo.GetValue(e, null));
        }

        clientes = clientes.Skip(nRegistroInic).Take(nRegistros);

        return await clientes.ToListAsync();
    }
Run Code Online (Sandbox Code Playgroud)

我得到的错误如下:

System.InvalidOperationException: LINQ 表达式 'DbSet .Where(c => True) .Where(c => c.Activo && True || False || False) .Where(c => True) .Where(c => True) ) .OrderBy(c => __propertyInfo_3.GetValue( obj: c, index: null))' 无法翻译。以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。

有什么想法吗?谢谢!

Jef*_*ado 6

您需要实际生成成员访问表达式,您所做的只是使用反射来获取某个对象的值,并将其作为表达式提供。那是行不通的,查询提供者将无法翻译它。

你需要做这样的事情:

if (!String.IsNullOrEmpty(sOrdenar))
{
    var type = typeof(Clientes_view);
    var prop = type.GetProperty(sOrdenar);
    if (prop != null)
    {
        var param = Expression.Parameter(type);
        var expr = Expression.Lambda<Func<Clientes_view, object>>(
            Expression.Convert(Expression.Property(param, prop), typeof(object)),
            param
        );
        if (nSentido == -1)
            clientes = clientes.OrderByDescending(expr);
        else
            clientes = clientes.OrderBy(expr);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止最好的解决方案在这里。 (2认同)