简体   繁体   English

将 linq 的方法转换为实体表达式以查询实体框架

[英]Convert a method to linq to entities expression for query the entity framework

I have this problem and I really don't know how to solve it.我有这个问题,我真的不知道如何解决它。 I asked two questions before abput this problem but didn't get to figure the right answer for my situation.在解决这个问题之前,我问了两个问题,但没有找到适合我情况的正确答案。 Here is the problem in details.这是详细的问题。 I have an interface and default implementation:我有一个接口和默认实现:

public interface IEntityPriceDefinition
{
    PriceDefinition PriceDefinition { get; }

    bool IsMatch(long additionId);

    bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId);

    bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
        long additionId);

    bool IsMatch(long? entityId, Task3 task);

    bool IsMatch(long? entityId, Task3 task, long additionId);
}

public class EntityPriceDefinition : IEntityPriceDefinition
    {
        private PriceDefinition _PriceDefinition;
        private Func<long?, bool> _IsEntityIdMatch;
        private Func<Task3, long?> _TaskValue;

        public PriceDefinition PriceDefinition { get { return _PriceDefinition; } }

        internal EntityPriceDefinition(
            PriceDefinition priceDefinition,
            Func<long?, bool> isEntityIdMatch,
            Func<Task3, long?> taskValue)
        {
            _PriceDefinition = priceDefinition;
            _IsEntityIdMatch = isEntityIdMatch;
            _TaskValue = taskValue;
        }

        public bool IsMatch(long additionId)
        {
            return PriceDefinition.AdditionsPrices.Any(x => x.AdditionId == additionId);
        }

        private bool IsMatch(long? inviterId, long? routeId, long? luggageTypeId)
        {
            bool isMatch = inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue;
            if (isMatch)
            {
                if (PriceDefinition.InviterId.HasValue && inviterId.HasValue)
                {
                    if (PriceDefinition.InviterId.Value != inviterId.Value) { isMatch = false; }
                }
                if (PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue)
                {
                    if (PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) { isMatch = false; }
                }
                if (PriceDefinition.RouteId.HasValue && routeId.HasValue)
                {
                    if (PriceDefinition.RouteId.Value != routeId.Value) { isMatch = false; }
                }
            }
            return isMatch;
        }

        public bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId)
        {
            return _IsEntityIdMatch(entityId) && IsMatch(inviterId, routeId, luggageTypeId);
        }

        public bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
            long additionId)
        {
            return IsMatch(entityId, inviterId, routeId, luggageTypeId) && IsMatch(additionId);
        }

        public bool IsMatch(long? entityId, Task3 task)
        {
            bool isMatch = _IsEntityIdMatch(_TaskValue(task)) &&
                IsMatch(task.InviterId, task.RouteId, task.LuggageTypeId);

            for (int i = 0; i < PriceDefinition.Rules.Count && isMatch == true; i++)
            {
                object value = task.GetFieldObjectValue(PriceDefinition.Rules[i].FieldName);
                isMatch = PriceDefinition.Rules[i].IsMatch((value ?? string.Empty).ToString());
            }
            return isMatch;
        }

        public bool IsMatch(long? entityId, Task3 task, long additionId)
        {
            return IsMatch(entityId ,task) && IsMatch(additionId);
        }
    }

I also have 3 classes that implement IEntityPriceDefinition using the default implementation.我还有 3 个使用默认实现实现IEntityPriceDefinition的类。 Here are two of those classes (the third is the same):这是其中两个类(第三个是相同的):

public class CustomerPriceDefinition : IEntityPriceDefinition, IDataEntity
    {
        private IEntityPriceDefinition _EntityPriceDefinition;

        public virtual long PriceDefinitionId { get; set; }
        public virtual long CustomerId { get; set; }
        public virtual PriceDefinition PriceDefinition { get; set; }

        public CustomerPriceDefinition()
        {
            _EntityPriceDefinition = new EntityPriceDefinition(
                PriceDefinition,
                entityId => entityId.HasValue && entityId.Value == CustomerId,
                t => t.CustomerId);
        }

        public bool IsMatch(long additionId)
        {
            return _EntityPriceDefinition.IsMatch(additionId);
        }

        public bool IsMatch(long? customerId, long? inviterId, long? routeId, long? luggageTypeId)
        {
            return _EntityPriceDefinition.IsMatch(customerId, inviterId, routeId, luggageTypeId);
        }

        public bool IsMatch(long? customerId, long? inviterId, long? routeId, long? luggageTypeId,
            long additionId)
        {
            return _EntityPriceDefinition.IsMatch(customerId, inviterId, routeId, luggageTypeId,
                additionId);
        }

        public bool IsMatch(long? customerId, Task3 task)
        {
            return _EntityPriceDefinition.IsMatch(customerId, task);
        }

        public bool IsMatch(long? customerId, Task3 task, long additionId)
        {
            return _EntityPriceDefinition.IsMatch(customerId, task, additionId);
        }
    }

public class WorkerPriceDefinition : IEntityPriceDefinition, IDataEntity
    {
        private IEntityPriceDefinition _EntityPriceDefinition;

        public virtual long PriceDefinitionId { get; set; }
        public virtual long WorkerId { get; set; }
        public virtual PriceDefinition PriceDefinition { get; set; }

        public WorkerPriceDefinition()
        {
            _EntityPriceDefinition = new EntityPriceDefinition(
                PriceDefinition,
                entityId => entityId.HasValue && entityId.Value == WorkerId,
                t => t.WorkerId);
        }

        public bool IsMatch(long additionId)
        {
            return _EntityPriceDefinition.IsMatch(additionId);
        }

        public bool IsMatch(long? workerId, long? inviterId, long? routeId, long? luggageTypeId)
        {
            return _EntityPriceDefinition.IsMatch(workerId, inviterId, routeId, luggageTypeId);
        }

        public bool IsMatch(long? workerId, long? inviterId, long? routeId, long? luggageTypeId,
            long additionId)
        {
            return _EntityPriceDefinition.IsMatch(workerId, inviterId, routeId, luggageTypeId,
                additionId);
        }

        public bool IsMatch(long? workerId, Task3 task)
        {
            return _EntityPriceDefinition.IsMatch(workerId, task);
        }

        public bool IsMatch(long? workerId, Task3 task, long additionId)
        {
            return _EntityPriceDefinition.IsMatch(workerId, task, additionId);
        }
    }

I have also repository interface and default implementation for those classes:我还有这些类的存储库接口和默认实现:

public interface IEntityPriceDefinitionRepository<T> : IRepository<T>
    where T : class, IEntityPriceDefinition, IDataEntity
{
    IEnumerable<T> GetMatchPrices(
        Guid companyId, bool? isSuggested, bool? isValid,
        long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
        Expression<Func<T, object>>[] includes);

    IEnumerable<T> GetMatchPrices(
        Guid companyId, bool? isSuggested, bool? isValid,
        long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
        Expression<Func<T, object>>[] includes);
}

public class EntityPriceDefinitionRepository<T> : BaseRepository<T>,
    IEntityPriceDefinitionRepository<T> where T : class,IEntityPriceDefinition, IDataEntity
{
    private IEnumerable<T> GetMatchPrices(
        Guid companyId, bool? isSuggested, bool? isValid,
        Expression<Func<T, bool>> isMatch,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
        Expression<Func<T, object>>[] includes)
    {
        var filters = new Expression<Func<T, bool>>[]{
            x => x.PriceDefinition.CompanyId == companyId,
            x => x.PriceDefinition.IsDeleted == false,
            x => !isValid.HasValue || x.PriceDefinition.IsValid == isValid.Value,
            x => !isSuggested.HasValue || x.PriceDefinition.IsSuggested == isSuggested.Value,
            isMatch
        };

        return GetQuery(filters, orderBy, includes);
    }

    public IEnumerable<T> GetMatchPrices(
        Guid companyId, bool? isSuggested, bool? isValid,
        long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
        Expression<Func<T, object>>[] includes)
    {
        return GetMatchPrices(companyId, isSuggested, isValid,
        //////////////////  THIS CAUSE THE EXCEPTION MENTIONED BELOW:  //////////////////
            x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId),
            orderBy, includes);
    }

    public IEnumerable<T> GetMatchPrices(
        Guid companyId, bool? isSuggested, bool? isValid,
        long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
        Expression<Func<T, object>>[] includes)
    {
        return GetMatchPrices(companyId, isSuggested, isValid,
        //////////////////  THIS CAUSE THE EXCEPTION MENTIONED BELOW:  //////////////////
            x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId, additionId),
            orderBy, includes);
    }        
}

And the classes repository classes are just:类存储库类只是:

 public class CustomerPriceDefinitionRepository :
        EntityPriceDefinitionRepository<CustomerPriceDefinition> { }

    public class WorkerPriceDefinitionRepository :
        EntityPriceDefinitionRepository<WorkerPriceDefinition> { }

The problem happend when I call CustomerPriceDefinitionRepository's GetMatchPrices method.当我调用 CustomerPriceDefinitionRepository 的 GetMatchPrices 方法时,问题发生了。 It always ends up with exception about the method that marked above:对于上面标记的方法,它总是以异常结束:

LINQ to Entities does not recognize the method 'Boolean IsMatch(System.Nullable 1[System.Int64], System.Nullable 1[System.Int64], System.Nullable 1[System.Int64], System.Nullable 1[System.Int64])' method, and this method cannot be translated into a store expression. LINQ 到 Entities 无法识别方法 'Boolean IsMatch(System.Nullable 1[System.Int64], System.Nullable 1[System.Int64], System.Nullable 1[System.Int64], System.Nullable ])' 方法,并且该方法不能翻译成 store 表达式。

Ladislav Mrnka's answered me here to use model defined functions but I want all my code to be in its classes and not in xml's. Ladislav Mrnka 在这里回答我使用 model 定义的函数,但我希望我的所有代码都在它的类中,而不是在 xml 中。 In addition, this code doesn't relevant to the huge scope that the edmx uses.此外,此代码与 edmx 使用的巨大 scope 无关。 In addition, I believe that in order to use model defined functions I will have to define 3 methods - one IsMatch for each sub class of IEntityPriceDefinition.此外,我相信为了使用 model 定义的函数,我必须定义 3 种方法 - IEntityPriceDefinition 的每个子 class 一个 IsMatch。

I really don't know how to solve this problem and what is the best solution for such case especially for such non-simple structure.我真的不知道如何解决这个问题以及这种情况的最佳解决方案是什么,尤其是对于这种非简单结构。 I will appriciate any help.我会给予任何帮助。

I added a static method in EntityPriceDefinition:我在 EntityPriceDefinition 中添加了一个 static 方法:

   public static Expression<Func<CustomerPriceDefinition, bool>> IsMatchExpression(
        long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId)
    {
        return x =>
            (entityId.HasValue && entityId.Value == x.CustomerId) &&
            (inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue) &&
            !(
                (x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                    x.PriceDefinition.InviterId.Value != inviterId.Value) ||

                (x.PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue &&
                    x.PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) ||

                (x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                    x.PriceDefinition.InviterId.Value != inviterId.Value)
            ) &&
            x.PriceDefinition.AdditionsPrices.Any(a => a.AdditionId == additionId);
    }

That way the expression knows how to transform it to query.这样,表达式就知道如何将其转换为查询。

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

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