【问题标题】:Convert a method to linq to entities expression for query the entity framework将方法转换为 linq 到实体表达式以查询实体框架
【发布时间】:2011-05-02 04:13:05
【问题描述】:

我有这个问题,我真的不知道如何解决它。在解决这个问题之前,我问了两个问题,但没有找到适合我情况的正确答案。这是详细的问题。 我有一个接口和默认实现:

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);
        }
    }

我还有 3 个使用默认实现实现 IEntityPriceDefinition 的类。这是其中两个类(第三个是相同的):

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);
        }
    }

我还有这些类的存储库接口和默认实现:

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);
    }        
}

类存储库类只是:

 public class CustomerPriceDefinitionRepository :
        EntityPriceDefinitionRepository<CustomerPriceDefinition> { }

    public class WorkerPriceDefinitionRepository :
        EntityPriceDefinitionRepository<WorkerPriceDefinition> { }

当我调用 CustomerPriceDefinitionRepository 的 GetMatchPrices 方法时,问题发生了。上面标记的方法总是以异常结束:

LINQ to Entities 无法识别方法 'Boolean IsMatch(System.Nullable1[System.Int64], System.Nullable1[System.Int64], System.Nullable1[System.Int64], System.Nullable1[System.Int64])' 方法,并且无法翻译此方法到商店表达式中。

Ladislav Mrnka 回答我 here 使用模型定义的函数,但我希望我的所有代码都在它的类中,而不是在 xml 中。此外,此代码与 edmx 使用的巨大范围无关。此外,我相信为了使用模型定义的函数,我必须定义 3 个方法 - IEntityPriceDefinition 的每个子类一个 IsMatch。

我真的不知道如何解决这个问题以及这种情况的最佳解决方案是什么,尤其是对于这种非简单的结构。我会给予任何帮助。

【问题讨论】:

  • 正如许多其他人已经告诉你的那样,问题是.IsMatch 没有等效的 SQL,因此 不能 被 Linq 翻译成有效的 SQL 语句-到实体。所以你需要找到另一种方式来表达这种情况,例如使用.StartsWith() 或其他东西。 或者:您需要从数据库中检索所有没有该表达式的实体,并且只使用 Linq-to-objects 过滤应用内存中的这些实体。
  • @marc_s:我理解这个问题,我正在寻找解决它的最佳方法。八现在我不知道该怎么做。
  • 如果您使用的是 SQL Server,是否可以将 IsMatch 编写为 SQLCLR 函数,然后将其用作 edmx 的导入函数?

标签: c# .net entity-framework linq-to-entities


【解决方案1】:

我在 EntityPriceDefinition 中添加了一个静态方法:

   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);
    }

这样表达式就知道如何将其转换为查询。

【讨论】:

    猜你喜欢
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-05
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多