【问题标题】:Error with an EF query with nested predicates - variable of type X referenced from scope but it is not defined带有嵌套谓词的 EF 查询出错 - 从范围引用的 X 类型变量但未定义
【发布时间】:2016-12-09 17:42:24
【问题描述】:

我正在尝试构建一个表达式,最终导致类似的查询

SELECT p.*
FROM MyEntity p
WHERE EXISTS(SELECT * 
             FROM filters
             WHERE (filter.type = 1 
                    AND filter.objectid = p.id 
                    AND filter.value = 1
                     OR filter.type = 1 
                    AND filter.objectid = p.id 
                    AND filter.value = 2))
  AND EXISTS(...)

显然它看起来并不完全一样,但这是大体的想法。 我使用PredicateBuilder 根据传入的过滤器构建查询,所以我有这样的东西:

var query = context.Set<MyEntity>().AsExpandable();

var predicate = PredicateBuilder.New<MyEntity>(true);

//loop through the group filters.  The filters in a group have an or relationship
foreach (FilterGroup group in filters)
{
    predicate = predicate.And(
                p => context.Set<FilteringValue>().AsExpandable().Any(getFilteringPredicate(p,group )) 
    );
}

return query.Where(predicate);

还有getFilteringPredicateMethod:

Expression<Func<FilteringValue,bool>> getFilteringPredicate(MyEntity p, FilterGroup filters) {

     var fPredicate = PredicateBuilder.New<FilteringValue>(true);
     foreach(var filter in filters.FilterList)
     {
         fPredicate= fPredicate.Or(fv => fv.objectid == p.Id && fv.Type== 1 && fv.value == filter.Value);
     }

     return fPredicate
}

这看起来比较简单,但是我得到了错误

从范围“”引用的“Models.MyEntity”类型的变量“p”,但未定义。

有没有办法将产品对象传递给 getFilteringPredicate() 方法? MyEntity 和 Filter 在 Entity Framework 中不相关。

【问题讨论】:

  • 不是一个完整的答案,但您应该在使用 Ors 时将 getFilteringPredicate 中的谓词构建器 fPredicate 初始化为 false。 var fPredicate = PredicateBuilder.New&lt;FilteringValue&gt;(true); 应该是 var fPredicate = PredicateBuilder.New&lt;FilteringValue&gt;(false);
  • 还有MyEntity and Filter are not related in Entity Framework.——他们可能应该是相关的。
  • 我将对此进行更详细的分析,我最初的测试看起来很好,我以为我有答案,但事实并非如此。我会给它第二次拍摄并发布答案
  • 您能否发布“至少部分”您的MyEntityFilterGroupFilterValue 的样子?它们都是在 EF 模型中映射的实体吗?
  • 拜托,看看我的回答,我想出了一个更好的方法来使用连接(是的,Linq 和 EF 支持它们),但现在真的没有时间。如果我的回答对你有用,请告诉我,我会发布替代方法(我喜欢 Linq、Expressions 和 LinqKit 顺便说一句:))

标签: c# entity-framework linq linq-to-sql predicatebuilder


【解决方案1】:

所以...我想我终于明白了,您想要关联两个表达式参数并构建一个复合查询(我所说的“复合”的非正式定义是指一个引用主查询参数的子查询(s)):

不幸的是,LinqKit 不支持多参数表达式“AFAIK”,这将是您的案例的完美匹配:

好吧,不管怎样……就这样吧。顺便说一下FilteringValuesMyEntities 只是两个DbSets,我只是碰巧使用LinqPad 来测试这个ATM(问题?):

void Main(string[] args)
{
    var entityQuery = MyEntities.AsExpandable();

    var filterGroups = GetFilterGroups();

    // Initialize with TRUE since no group filter implies Everything matches
    var predicate = PredicateBuilder.New<MyEntity>(true);

    var filteringValueQuery = FilteringValues.AsExpandable();

    foreach (var g in filterGroups)
    {
        if (!g.FilterList.Any())
        {
            // If we have no filters in the group, skip
            continue;
        }
        var expressionForGroupFilters = BuildExpressionForGroupFilters(g.FilterList);
        predicate = predicate.And(entity => filteringValueQuery.Any(filteringValue => expressionForGroupFilters.Invoke(entity, filteringValue)));
    }

    entityQuery = entityQuery.Where(predicate);

    var data = entityQuery.ToList();

    data.Dump();
}

public static Expression<Func<MyEntity, FilteringValue, bool>> BuildExpressionForSingleFilter(Filter groupFilter)
{
    var value = groupFilter.Value;
    return (entity, filteringValue) =>
        filteringValue.Type == 1
        && filteringValue.ObjectId == entity.Id
        && filteringValue.Value == value;
}

public static Expression<Func<MyEntity, FilteringValue, bool>> BuildExpressionForGroupFilters(IReadOnlyCollection<Filter> groupFilters)
{
    Expression<Func<MyEntity, FilteringValue, bool>> result = null;

    foreach (var groupFilter in groupFilters)
    {
        var expression = BuildExpressionForSingleFilter(groupFilter);
        if (result == null)
        {
            result = expression;
            continue;
        }

        var tempResult = result.Expand();
        result = (entity, filteringValue) => tempResult.Invoke(entity, filteringValue) || expression.Invoke(entity, filteringValue);
    }

    return result.Expand();
}

public static FilterGroup CreateFilterGroupWithValues(params int[] values)
{
    var filterList = values
        .Select(x => new Filter { Value = x })
        .ToList();

    return new FilterGroup { FilterList = filterList };
}

public static IEnumerable<FilterGroup> GetFilterGroups()
{
    return new[] {CreateFilterGroupWithValues(0, 2, 4), CreateFilterGroupWithValues(1)};
}

public class Filter
{
    public int Value { get; set; }
}

public class FilterGroup
{
    public FilterGroup()
    {
        FilterList = new List<Filter>();
    }

    public List<Filter> FilterList { get; set; }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    相关资源
    最近更新 更多