LINQ到实体 - 建筑where子句测试中的许多藏品一对多的关系LINQ到实体 - 建筑where

2019-06-01 02:14发布

所以,我使用LINQ的实体框架。 我有2个实体: ContentTag 。 他们彼此多对一对多的关系。 Content可以有很多TagsTag可以有很多Contents 。 所以,我想编写一个查询来选择所有内容,其中任何标签名称是等于blah

这些实体都具有其他实体的属性(但没有标识)的集合。 这是我在挣扎。 我有一个自定义表达式Contains (所以,谁可以帮我,你可以认为我可以做一个“包含”为集合)。 我得到这个表达来自: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1

编辑1

我最终找到我自己的答案。

Answer 1:

阅读有关后PredicateBuilder ,看完所有的人发给我的精彩帖子,发布在其他网站上,然后阅读更多关于组合谓词和规范功能映射 ..呵呵,我从拿起一个位在LINQ查询调用函数 (一些这些类都是从这些页面获取)。

我终于有了一个解决方案! 虽然有是有点砍死了一块...

让我们砍死件在与:(

我不得不使用反射器和复制标记为内部的ExpressionVisitor类。 然后我不得不做出一些细微的变化,得到它的工作。 我不得不创建两个例外(因为它是newing内部异常我也不得不改变ReadOnlyCollection()方法的返回从:

return sequence.ToReadOnlyCollection<Expression>();

至:

return sequence.AsReadOnly();

我会发布类,但它是相当大的,我不想扰乱这个帖子任何超过它已经将是。 我希望在未来的类可以从我的媒体库中删除,而微软将使其公开。 继续...

我加了ParameterRebinder类:

public class ParameterRebinder : ExpressionVisitor {
        private readonly Dictionary<ParameterExpression, ParameterExpression> map;

        public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) {
            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
        }

        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) {
            return new ParameterRebinder(map).Visit(exp);
        }

        internal override Expression VisitParameter(ParameterExpression p) {
            ParameterExpression replacement;
            if (map.TryGetValue(p, out replacement)) {
                p = replacement;
            }
            return base.VisitParameter(p);
        }
    }

然后,我添加了一个ExpressionExtensions类:

public static class ExpressionExtensions {
        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) {
            // build parameter map (from parameters of second to parameters of first)
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with parameters from the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // apply composition of lambda expression bodies to parameters from the first expression 
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
            return first.Compose(second, Expression.And);
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
            return first.Compose(second, Expression.Or);
        }
    }

而且我加了最后一节课是PredicateBuilder:

public static class PredicateBuilder {
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

}

这是我的结果......我能执行此代码,并取回所产生的“内容”实体具有不同于我在寻找标签匹配的“标签”的实体!

    public static IList<Content> GetAllContentByTags(IList<Tag> tags) {
        IQueryable<Content> contentQuery = ...

        Expression<Func<Content, bool>> predicate = PredicateBuilder.False<Content>();

        foreach (Tag individualTag in tags) {
            Tag tagParameter = individualTag;
            predicate = predicate.Or(p => p.Tags.Any(tag => tag.Name.Equals(tagParameter.Name)));
        }

        IQueryable<Content> resultExpressions = contentQuery.Where(predicate);

        return resultExpressions.ToList();
    }

请让我知道如果有人需要帮助,这同样的事情,如果你想我给你发送文件,对于这一点,或者只是需要更多的信息。



Answer 2:

总结起来...

contentQuery.Where(
    content => content.Tags.Any(tag => tags.Any(t => t.Name == tag.Name))
);

所以是你期待什么?

我有点困惑。



Answer 3:

这就是问题的自身要求:

contentQuery.Where(
    content => content.Tags.Any(tag => tag.Name == "blah")
);

我不知道什么样的思维过程是去提问的代码,真的,我不完全知道正是它真的这样做。 有一件事我真的很肯定的是,.AsQueryable()调用是完全没有必要的 - 要么.tags添加已经是一个IQueryable,或.AsQueryable()仅仅是将假的你 - 增加在额外要求那里不需要是任何。



Answer 4:

该错误与'标记的变量。 LINQ到实体不支持的参数是值的集合。 简单地调用tags.AsQueryable() - 如在ealier答案建议 - 将无法工作或者是因为默认的内存LINQ查询提供不兼容LINQ到实体(或其他关系提供者)。

作为一种变通方法,您可以手动建立使用表达式API过滤器(见本论坛后 ),并将其应用如下:

var filter = BuildContainsExpression<Element, string>(e => e.Name, tags.Select(t => t.Name));
var query = source.Where(e => e.NestedValues.Any(filter));


Answer 5:

tags.Select(testTag => testTag.Name)

哪里的标签变量被初始化从? 它是什么?



Answer 6:

注:请编辑的问题本身,而不是一个答案回复-这不是一个讨论话题,他们可以在任何时间重新整理自己

如果你正在寻找的是标有一组标签中的任意一个全部内容:

IEnumerable<Tag> otherTags;
...
var query = from content in contentQuery
            where content.Tags.Intersection(otherTags).Any()
            select content;

它看起来像你可能会使用LINQ to SQL,在这种情况下,如果你写一个存储过程做到这一点可能会更好这样一条:使用LINQ要做到这一点可能不会SQL Server上运行 - 这是非常有可能会尝试从下拉一切contentQuery和获取所有.Tags收藏。 我必须真正建立一个服务器来检查,但。



文章来源: LINQ to entities - Building where clauses to test collections within a many to many relationship