所以,我使用LINQ的实体框架。 我有2个实体: Content
和Tag
。 他们彼此多对一对多的关系。 Content
可以有很多Tags
和Tag
可以有很多Contents
。 所以,我想编写一个查询来选择所有内容,其中任何标签名称是等于blah
这些实体都具有其他实体的属性(但没有标识)的集合。 这是我在挣扎。 我有一个自定义表达式Contains
(所以,谁可以帮我,你可以认为我可以做一个“包含”为集合)。 我得到这个表达来自: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1
编辑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();
}
请让我知道如果有人需要帮助,这同样的事情,如果你想我给你发送文件,对于这一点,或者只是需要更多的信息。
总结起来...
contentQuery.Where(
content => content.Tags.Any(tag => tags.Any(t => t.Name == tag.Name))
);
所以是你期待什么?
我有点困惑。
这就是问题的自身要求:
contentQuery.Where(
content => content.Tags.Any(tag => tag.Name == "blah")
);
我不知道什么样的思维过程是去提问的代码,真的,我不完全知道正是它真的这样做。 有一件事我真的很肯定的是,.AsQueryable()调用是完全没有必要的 - 要么.tags添加已经是一个IQueryable,或.AsQueryable()仅仅是将假的你 - 增加在额外要求那里不需要是任何。
该错误与'标记的变量。 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));
tags.Select(testTag => testTag.Name)
哪里的标签变量被初始化从? 它是什么?
注:请编辑的问题本身,而不是一个答案回复-这不是一个讨论话题,他们可以在任何时间重新整理自己
如果你正在寻找的是标有一组标签中的任意一个全部内容:
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