简体   繁体   English

无法翻译 Linq 表达式错误 Entity Framework Core 3

[英]Linq expression could not be translated Error Entity Framework Core 3

I am on a project and got some problem with data accessing.我在一个项目中,在数据访问方面遇到了一些问题。 I use EF core and I have these stack trace.我使用 EF 核心并且我有这些堆栈跟踪。

First code executed执行的第一个代码

public static void Main(){
 EntityServiceBase<Product> manager = new EntityServiceBase(new EFProductDal());//efproductdal for to access database
 Product result = manager.GetByPrimaryKey(5);
}

Second file code executed执行的第二个文件代码

At the code IEntity is an empty interface to determine database objects在代码中 IEntity 是一个确定数据库对象的空接口
IEntityRepostiory has EF codes to access database which is shown in third code part at the belong IEntityRepostiory 具有访问数据库的 EF 代码,该代码显示在属于
PrimaryKeyComparable has compare func to check if primary key of an object is equal to given key PrimaryKeyComparable 具有比较功能来检查对象的主键是否等于给定的键

using System;
using System.Collections.Generic;
using ECommercial.Core.DataAccess;
using ECommercial.Core.Entities;

namespace ECommercial.Core.Business
{
    public abstract class EntityServiceBase<TEntity> : IService<TEntity> 
        where TEntity :class,IEntity, new() // IENTITY IS AN EMPTY INTERFACE TO JUST DETERMINE DATABASE ENTITIES
    {
        private IEntityRepository<TEntity> _entityRepository;

        public EntityServiceBase(IEntityRepository<TEntity> entityRepository)
        {
            _entityRepository = entityRepository;
        }

        public TEntity GetByPrimaryKey(Object key)
        {
            PrimaryKeyComparable primaryKeyComparable = new PrimaryKeyComparable();
            return _entityRepository.Get(o=>primaryKeyComparable.comparePrimaryKey<TEntity>(o,key));
        }
    }
}

Third code part executed执行的第三个代码部分

At the code context is EF dbcontext在代码上下文是 EF dbcontext
filter is given filter which is o=>primaryKeyComparable.comparePrimaryKey(o,key) the second code file.过滤器被赋予过滤器,即 o=>primaryKeyComparable.comparePrimaryKey(o,key) 第二个代码文件。 The error occurs at .SingleOrDefault(filter) part.错误发生在 .SingleOrDefault(filter) 部分。 If I delete it function works well.如果我删除它,功能运行良好。

public TEntity Get(Expression<Func<TEntity, bool>> filter)
        {
            using (var context=new TContext()){
                TEntity result = context.Set<TEntity>().SingleOrDefault(filter);
                return result;
            }
        }

ComparePrimaryKey function比较主键函数

public bool comparePrimaryKey<TEntity>(TEntity entity,Object value)
            where TEntity:class,IEntity,new()
        {
            Type entityType = typeof(TEntity);
            FieldInfo[] fields = entityType.GetFields();
            FieldInfo found =null;
            foreach(var field in fields){
                Attribute attribute=field.GetCustomAttribute(typeof(PrimaryKeyFieldAttribute));
                if(attribute!=null){
                    found=field;
                    break;
                }
            }
            if(found!=null){
                Type foundDeclaringType= found.DeclaringType;
                Type valueDeclaringType = value.GetType().DeclaringType;
                if((foundDeclaringType.IsSubclassOf(valueDeclaringType)) ||valueDeclaringType.IsSubclassOf(foundDeclaringType) || valueDeclaringType==foundDeclaringType)
                {
                    return entity.Equals(value);
                }
                throw new InvalidCastException("Given entity's primary key must have same or child-base related declaration type with key object compared");
            }
            throw new CustomAttributeFormatException("The Entity Has Any field has PrimaryKeyFieldAttribute attribute. Must be PrimaryKeyAttribute on primary key field.");
        }

The Error Message (I think english parts is enough to understand)错误信息(我认为英文部分足以理解)

ERROR OCCURS AT THE THIRD FILE AT .SingleOrDefault(filter) PART错误发生在 .SingleOrDefault(filter) 部分的第三个文件

Exception has occurred: CLR/System.InvalidOperationException
'System.InvalidOperationException' türünde özel durum Microsoft.EntityFrameworkCore.dll öğesinde oluştu, fakat kullanıcı kodunda işlenmedi: 'The LINQ expression 'DbSet<Product>
    .Where(p => new PrimaryKeyComparable().comparePrimaryKey<Product>(
        entity: p, 
        value: __key_0))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
   konum Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|8_0(ShapedQueryExpression translated, <>c__DisplayClass8_0& )
   konum Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   konum Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   konum System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   konum System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   konum Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   konum Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   konum System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   konum System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   konum Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   konum Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   konum Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   konum Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   konum Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   konum Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   konum Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   konum Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   konum System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
   konum ECommercial.Core.DataAccess.EntitiyFramework.EFIEntityRepositoryBase`2.Get(Expression`1 filter) C:\Users\nihaSWin\Desktop\ECommercial\ECommercial.Core\DataAccess\EntitiyFramework\EFIEntityRepositoryBase.cs içinde: 36. satır
   konum ECommercial.Core.Business.EntityServiceBase`1.GetByPrimaryKey(Object key) C:\Users\nihaSWin\Desktop\ECommercial\ECommercial.Core\Business\EntityServiceBase.cs içinde: 26. satır
   konum ECommercial.MVC.Startup..ctor(IConfiguration configuration) C:\Users\nihaSWin\Desktop\ECommercial\ECommercial.MVC\Startup.cs içinde: 19. satır

So it looks like you're trying to use reflection to determine the primary key and query based on that.所以看起来你正在尝试使用反射来确定主键和基于它的查询。 You can't use a method like that directly in an expression and expect EF to untangle what it does and turn it into sql.您不能直接在表达式中使用这样的方法,并期望 EF 解开它的作用并将其转换为 sql。

However, you could use reflection to generate an expression and use that directly instead.但是,您可以使用反射来生成表达式并直接使用它。

public Expression<Func<TEntity, bool>> comparePrimaryKey<TEntity>(object value)
{
    var parm = Expression.Parameter(typeof(TEntity), "e");
    var objType = value.GetType();
    return Expression.Lambda<Func<TEntity, bool>>(
        typeof(TEntity)
            .GetFields()
            .Where(f => f.GetCustomAttribute(typeof(PrimaryKeyFieldAttribute)) != null)
            .Select(f => (Expression)Expression.Equal(
                Expression.MakeMemberAccess(parm, f),
                Expression.Constant(
                    (objType == f.FieldType)
                        ? value
                        : objType.GetField(f.Name).GetValue(value),
                    f.FieldType)
            ))
            .Aggregate((l, r) => Expression.AndAlso(l, r)),
        parm);
}

//...

return _entityRepository.Get(primaryKeyComparable.comparePrimaryKey<TEntity>(key));

Though I would recommend using dbContext.Model metadata to discover the primary key, instead of depending on reflection and attribute conventions.虽然我建议使用 dbContext.Model 元数据来发现主键,而不是依赖于反射和属性约定。

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

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