编写扩展方法以帮助查询多对多关系

|| 我试图写一个ѭ0来重构我正在写的linq多对多查询。我正在尝试检索已用参数传递给我的方法的集合中的任何“ 2”标记的“ 1”的集合。 以下是相关的实体及其一些属性:   发布      标量特性:
PostID
PostDate
     导航属性:
PostTags
     PostTag      标量特性:
PostTagID
PostID
TagID
     导航属性:
Post
Tag
     标签      标量性质:
TagID
     导航属性:
PostTags
这是我目前正在使用的查询,效果很好:
public IEnumerable<Post> GetPostsByTags(IEnumerable<Tag> tags)
{
    return from pt in context.PostTags
           from t in tags
           where pt.TagID == t.TagID &&
                 pt.Post.PostDate != null
           orderby pt.Post.PostDate descending
           select pt.Post;               
}   
这是我努力创建的
extension method
(可能不正确)的开始:
public static IEnumerable<TResult> SelectRange<TSource, TResult>(
    this IEnumerable<TSource> collection,
    Func<IEnumerable<TSource>, IEnumerable<TResult>> selector)
{
    return selector(collection);
}
并对原始查询进行理想的简化:
public IEnumerable<Post> GetPostsByTags(IEnumerable<Tag> tags)
{
    return from p in context.Posts
           where p.PostTags.SelectRange(x => ?) &&
                 p.PostDate != null                    
           orderby p.PostDate descending
           select p;
}
非常感谢您编写此“ 0”的帮助或执行此查询的任何其他更有效的方法。     
已邀请:
        我认为您的原始查询很好,您只需要处理重复的帖子。在末尾添加一个独特的字符。或者,您可以像这样使用Any方法。
public IEnumerable<Post> GetPostsByTags(IEnumerable<Tag> tags)
{
    return from p in context.Posts
           where p.PostTags.Any(pt => tags.Any(t => t.TagID == pt.TagID)) &&
                 p.PostDate != null                    
           orderby p.PostDate descending
           select p;
}
编辑-添加了另一个Any语句     
        实现目标的最有效方法可能是使用内置的
join
子句,该子句专门用于这种多对多关系:
from pt in PostTags
where pt.Post.PostDate != null
join t in tags on pt.TagID equals t.TagID
orderby pt.Post.PostDate descending
select pt.Post;
它不是以前的选项“更正确”:在发布问题时,您已经可以使用某些功能。但这绝对是在语法和性能方面更巧妙的工作方式。     
        实际上,我必须针对这个问题提出自己的解决方案,因为我正在处理的数据源与实体表(odbc连接上的DBase 4)不兼容,该实体具有很多对很多的表关系,而是必须写出一个很长的linq的join和group块的方法,我创建了两个扩展方法   现在请注意,我只处理从   数据源本质上是该程序仅用于的数据集   历史数据,并且不接受新的输入或更改,因此我不   确保这些扩展方法能适应任何实际情况   数据更新插入或删除等 (为了方便阅读,我将每个参数都包装在其自己的行上)
public static IEnumerable<TResult> ManyToManyGroupBy
    <TLeft, TRight, TMiddle, TLeftKey, TRightKey, TGroupKey, TResult>
    (
      this IEnumerable<TLeft> Left, 
      IEnumerable<TRight> Right, 
      IEnumerable<TMiddle> Middle, 
      Func<TLeft, TLeftKey> LeftKeySelector, 
      Func<TMiddle, TLeftKey> MiddleLeftKeySelector, 
      Func<TRight, TRightKey> RightKeySelector, 
      Func<TMiddle, TRightKey> MiddleRightKeySelector, 
      Func<TLeft, TGroupKey> GroupingSelector, 
      Func<TGroupKey, IEnumerable<TRight>, TResult> Selector
    )
{
  return Left
   .Join(Middle, LeftKeySelector, MiddleLeftKeySelector, (L, M) => new { L, M })
   .Join(Right, LM => MiddleRightKeySelector(LM.M), RightKeySelector, (LM, R) => new { R, LM.L })
   .GroupBy(LR => GroupingSelector(LR.L))
   .Select(G => Selector(G.Key, G.Select(g => g.R)));
}

public static IEnumerable<TResult> ManyToManySelect
    <TLeft, TRight, TMiddle, TLeftKey, TRightKey, TResult>
    (
      this IEnumerable<TLeft> Left, 
      IEnumerable<TRight> Right, 
      IEnumerable<TMiddle> Middle, 
      Func<TLeft, TLeftKey> LeftKeySelector, 
      Func<TMiddle, TLeftKey> MiddleLeftKeySelector, 
      Func<TRight, TRightKey> RightKeySelector, 
      Func<TMiddle, TRightKey> MiddleRightKeySelector, 
      Func<TLeft, TRight, TResult> Selector
    )
{
  return Left
   .Join(Middle, LeftKeySelector, MiddleLeftKeySelector, (L, M) => new { L, M })
   .Join(Right, LM => MiddleRightKeySelector(LM.M), RightKeySelector, (LM, R) => new { R, LM.L })
    .Select(LR => Selector(LR.L, LR.R));
}
它们是相当长的方法,但是它们涵盖了通过中间表将两个表连接在一起以及按任何特定的Left项或left项的属性进行分组 使用它们看起来像这样(如上所述,为了方便阅读,我将每个参数都包装在其自己的行上)
  var EmployeesCoursesTest = Employees.ManyToManySelect
  (
   Courses, 
   CourseParticipations, 
   E => E.SS, 
   CP => CP.SS, 
   C => C.EVENTNO, 
   CP => CP.EVENTNO, 
   (E, C) => new
   {
    C.EVENTNO,
    C.START_DATE,
    C.END_DATE,
    C.HOURS,
    C.SESSIONS,
    Trainings.First(T => T.TRGID == C.TRGID).TRAINING,
    Instructors.First(I => I.INSTRUCTID == C.INSTRUCTID).INSTRUCTOR,
    Locations.First(L => L.LOCATIONID == C.LOCATIONID).LOCATION,
    Employee = E
   }
  );

  var EmployeesCoursesGroupByTest = Employees.ManyToManyGroupBy
  (
   Courses, 
   CourseParticipations, 
   E => E.SS, 
   CP => CP.SS, 
   C => C.EVENTNO, 
   CP => CP.EVENTNO, 
   E => E,
   (E, Cs) => new
   {
    Employee = E,
    Courses = Cs
   }
  );
也许它将对您有所帮助,我本人倾向于远离查询语法,所以我几乎只使用Linq的方法语法,因此编写此类扩展方法只是我现在考虑的一种方式。     

要回复问题请先登录注册