简体   繁体   English

.Net Core 5 Rest Api 实体框架 Linq 从 Z9EBA623737023BF782 获取记录列表时出现表达式翻译错误

[英].Net Core 5 Rest Api Entity Framework Linq Expression Translation Error While Getting Record List From Controller

I am working on a project and I got an error while getting queried list.我正在做一个项目,在获取查询列表时出现错误。 I will tell on code block below.我将在下面的代码块中讲述。

//AT REPOSITORY SIDE THIS FUNCTION GETS FILTERED LIST OF RECORDS
        public List<TEntity> GetList(Expression<Func<TEntity, bool>> filter)
        {
            using (var context=new MyContext()){
                return context.Set<TEntity>().Where(filter).ToList();
            }
        }
//AT ENTITY SIDE THIS FUNCTION CHECKS IF ALL PROPERTIES ARE EQUAL WITH THE GIVEN OBJECT
        public bool PublicPropertiesEqual(object which) 
        {
            var type = this.GetType();
            var whichType = which.GetType();
            var whichProperties = whichType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if(whichProperties.Any(x => x.Name == pi.Name)){
                    object selfValue = type.GetProperty(pi.Name).GetValue(this, null);
                    object whichValue = type.GetProperty(pi.Name).GetValue(which,null);
                    if (selfValue != whichValue && (selfValue == null || !selfValue.Equals(whichValue)))
                    {
                        return false;
                    }
                }
            }
            return true;
        }
//AT CONTROLLER SIDE ONLY CALLED REPO GETLIST FUNCTION WITH GIVEN FILTER
        [HttpGet]
        public IActionResult GetList([FromQuery] TEntity  query)
        {
            List<TEntity> res = _repo.GetList(x = x.PublicPropertiesEqual(query));
            return Ok(res);
        }

PROBLEM问题

When I execute the code I get an error like that当我执行代码时,我收到这样的错误

InvalidOperationException: The LINQ expression 'DbSet().Where(c => c.PublicPropertiesEqual(__query_0))' could not be translated. InvalidOperationException:无法翻译 LINQ 表达式 'DbSet().Where(c => c.PublicPropertiesEqual(__query_0))'。 Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。 See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

So I cant get records from database.所以我无法从数据库中获取记录。 I tried to write custom expression tree showed below at the controller side and it also doesn't work.我尝试在 controller 端编写如下所示的自定义表达式树,但它也不起作用。

        [HttpGet]
        public IActionResult GetList([FromQuery] TEntity  query)
        {
            var param = Expression.Parameter(typeof(TEntity));
            var lambda = Expression.Lambda<Func<TEntity,bool>>(
                Expression.Call(
                    param, 
                    _entityType.GetMethod("PublicPropertiesEqual"),
                    Expression.Constant(query)
                ),
                param
            );
            List<TEntity> res = _repo.GetList(lambda);
            return Ok(res);
        }

And the error after executed this code以及执行此代码后的错误

InvalidOperationException: The LINQ expression 'DbSet().Where(c => c.PublicPropertiesEqual(Customer))' could not be translated. InvalidOperationException:无法翻译 LINQ 表达式“DbSet().Where(c => c.PublicPropertiesEqual(Customer))”。 REST OF THE ERROR IS SAME ABOVE... REST 的错误同上...

As a conclusion, how can I filter the query with using PublicPropertiesEqual(object) function?作为结论,如何使用 PublicPropertiesEqual(object) function 过滤查询?

It is easy to write such function, but you have to filter out navigation properties by yourself:写这样的 function 很容易,但是你必须自己过滤掉导航属性:

public static Expression<Func<T, bool>> PublicPropertiesEqual<T>(T entity)
{
    var props = typeof(T).GetProperties();
    var entityParam = Expression.Parameter(typeof(T), "e");
    var entityExpr = Expression.Constant(entity);

    var equality = props.Select(p => Expression.Equal(
        Expression.MakeMemberAccess(entityParam, p),
        Expression.MakeMemberAccess(entityExpr, p)
    ));

    var predicate = equality.Aggregate(Expression.AndAlso);
    return Expression.Lambda<Func<T, bool>>(predicate, entityParam);
}

Usage is simple:用法很简单:

List<TEntity> res = _repo.GetList(PublicPropertiesEqual(query));

Anyway if you have access to DbContext better to pass it to the function and reuse IModel information.无论如何,如果您可以访问DbContext最好将其传递给 function 并重用IModel信息。

public static Expression<Func<T, bool>> PublicPropertiesEqual<T>(DbContext ctx, T entity)
{
    var et = ctx.Model.FindEntityType(typeof(T));
    if (et == null)
        throw new InvalidOperationException();

    var props = et.GetProperties();
    var entityParam = Expression.Parameter(typeof(T), "e");
    var entityExpr = Expression.Constant(entity);

    var equality = props
        .Where(p => !p.IsForeignKey() && !p.IsIndexerProperty())
        .Select(p => Expression.Equal(
            Expression.MakeMemberAccess(entityParam, p.PropertyInfo),
            Expression.MakeMemberAccess(entityExpr, p.PropertyInfo)
        ));

    var predicate = equality.Aggregate(Expression.AndAlso);
    return Expression.Lambda<Func<T, bool>>(predicate, entityParam);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM