IQueryable<TOuter>的扩展方法中提供了 INNER JOIN,GROUP JOIN但是没有提供LEFT JOIN

GROUP JOIN适用于一对多的场景,如果关联的GROUP没有条目,会显示List条目为0,这一点其实也是LEFT join,

但是如果反过来,对于多对一的场景,虽然可以用GROUP JOIN,但是对于单一的条目却还要用List进行包装,就有点逻辑的冗余。

这个时候Left join就派上用场了

  /// <summary>
/// InnerJoin
/// </summary>
/// <typeparam name="TInner"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TModel"></typeparam>
/// <param name="outerKeySelector"></param>
/// <param name="innerKeySelector"></param>
/// <param name="resultSelector"></param>
/// <returns></returns>
public List<TModel> GetInnerJoin<TInner, TKey, TModel>(
Expression<Func<TEntity, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Join(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetLeftJoin<TInner, TKey, TModel>(
Expression<Func<TEntity, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().LeftOuterJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetLeftJoin<TInner, TKey, TModel>(
Expression<Func<TEntity, bool>> predicate,
Expression<Func<TEntity, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Where(predicate).LeftOuterJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetGroupJoin<TInner, TKey, TModel>(
Expression<Func<TEntity, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TEntity, IEnumerable<TInner>, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().GroupJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetGroupJoin<TInner, TKey, TModel>(
Expression<Func<TEntity, bool>> predicate,
Expression<Func<TEntity, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TEntity, IEnumerable<TInner>, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Where(predicate).GroupJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
}

所以对于 INNER JOIN,LEFT JOIN,GROUP JOIN的使用场景

INNER JOIN适合各种场景,数据平面显示(内连接查询)

Left join适合各种场景,数据平面显示(外连接查询)

GROUP JOIN更适合于一对多,关联项以组的形式包装(外连接查询)

 //List<dynamic> list = companyDAL.GetGroupJoin<Product, int, dynamic>(m => m.ID, m => (int)m.CompanyID, (o, i) =>new {o,i });
//List<dynamic> list = productDAL.GetGroupJoin<Company, int, dynamic>( m => (int)m.CompanyID,m => m.ID, (o, i) => new { o, i }); List<dynamic> list = productDAL.GetLeftJoin<Company, dynamic, dynamic>(m => m.ID < , m => new { m.CompanyID, m.Second }, m => new { CompanyID = m.ID, m.Second }, (o, i) => new { o, i });
//List<dynamic> list = productDAL.GetInnerJoin<Company, int, dynamic>(m => (int)m.CompanyID, m => m.ID, (o, i) => new { o, i });

使用dynamic简化泛型参数

        /// <summary>
/// InnerJoin
/// </summary>
/// <typeparam name="TInner"></typeparam>
/// <typeparam name="TModel"></typeparam>
/// <param name="outerKeySelector"></param>
/// <param name="innerKeySelector"></param>
/// <param name="resultSelector"></param>
/// <returns></returns>
public List<TModel> GetInnerJoin<TInner, TModel>(
Expression<Func<TEntity, dynamic>> outerKeySelector,
Expression<Func<TInner, dynamic>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Join(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetLeftJoin<TInner, TModel>(
Expression<Func<TEntity, dynamic>> outerKeySelector,
Expression<Func<TInner, dynamic>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().LeftOuterJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetLeftJoin<TInner, TModel>(
Expression<Func<TEntity, bool>> predicate,
Expression<Func<TEntity, dynamic>> outerKeySelector,
Expression<Func<TInner, dynamic>> innerKeySelector,
Expression<Func<TEntity, TInner, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Where(predicate).LeftOuterJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetGroupJoin<TInner, TModel>(
Expression<Func<TEntity, dynamic>> outerKeySelector,
Expression<Func<TInner, dynamic>> innerKeySelector,
Expression<Func<TEntity, IEnumerable<TInner>, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().GroupJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
} public List<TModel> GetGroupJoin<TInner, TModel>(
Expression<Func<TEntity, bool>> predicate,
Expression<Func<TEntity, dynamic>> outerKeySelector,
Expression<Func<TInner, dynamic>> innerKeySelector,
Expression<Func<TEntity, IEnumerable<TInner>, TModel>> resultSelector) where TInner : class
{
var query = dbContext.Set<TEntity>().Where(predicate).GroupJoin(dbContext.Set<TInner>(), outerKeySelector, innerKeySelector, resultSelector);
return query.ToList();
}

扩展方法

        public static IQueryable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IQueryable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TOuter, TInner, TResult>> resultSelector)
{ // generic methods
var selectManies = typeof(Queryable).GetMethods()
.Where(x => x.Name == "SelectMany" && x.GetParameters().Length == )
.OrderBy(x => x.ToString().Length)
.ToList();
var selectMany = selectManies.First();
var select = typeof(Queryable).GetMethods().First(x => x.Name == "Select" && x.GetParameters().Length == );
var where = typeof(Queryable).GetMethods().First(x => x.Name == "Where" && x.GetParameters().Length == );
var groupJoin = typeof(Queryable).GetMethods().First(x => x.Name == "GroupJoin" && x.GetParameters().Length == );
var defaultIfEmpty = typeof(Queryable).GetMethods().First(x => x.Name == "DefaultIfEmpty" && x.GetParameters().Length == ); // need anonymous type here or let's use Tuple
// prepares for:
// var q2 = Queryable.GroupJoin(db.A, db.B, a => a.Id, b => b.IdA, (a, b) => new { a, groupB = b.DefaultIfEmpty() });
var tuple = typeof(Tuple<,>).MakeGenericType(
typeof(TOuter),
typeof(IQueryable<>).MakeGenericType(
typeof(TInner)
)
);
var paramOuter = Expression.Parameter(typeof(TOuter));
var paramInner = Expression.Parameter(typeof(IEnumerable<TInner>));
var groupJoinExpression = Expression.Call(
null,
groupJoin.MakeGenericMethod(typeof(TOuter), typeof(TInner), typeof(TKey), tuple),
new Expression[]
{
Expression.Constant(outer),
Expression.Constant(inner),
outerKeySelector,
innerKeySelector,
Expression.Lambda(
Expression.New(
tuple.GetConstructor(tuple.GetGenericArguments()),
new Expression[]
{
paramOuter,
Expression.Call(
null,
defaultIfEmpty.MakeGenericMethod(typeof (TInner)),
new Expression[]
{
Expression.Convert(paramInner, typeof (IQueryable<TInner>))
}
)
},
tuple.GetProperties()
),
new[] {paramOuter, paramInner}
)
}
); // prepares for:
// var q3 = Queryable.SelectMany(q2, x => x.groupB, (a, b) => new { a.a, b });
var tuple2 = typeof(Tuple<,>).MakeGenericType(typeof(TOuter), typeof(TInner));
var paramTuple2 = Expression.Parameter(tuple);
var paramInner2 = Expression.Parameter(typeof(TInner));
var paramGroup = Expression.Parameter(tuple);
var selectMany1Result = Expression.Call(
null,
selectMany.MakeGenericMethod(tuple, typeof(TInner), tuple2),
new Expression[]
{
groupJoinExpression,
Expression.Lambda(
Expression.Convert(Expression.MakeMemberAccess(paramGroup, tuple.GetProperty("Item2")),
typeof (IEnumerable<TInner>)),
paramGroup
),
Expression.Lambda(
Expression.New(
tuple2.GetConstructor(tuple2.GetGenericArguments()),
new Expression[]
{
Expression.MakeMemberAccess(paramTuple2, paramTuple2.Type.GetProperty("Item1")),
paramInner2
},
tuple2.GetProperties()
),
new[]
{
paramTuple2,
paramInner2
}
)
}
); // prepares for final step, combine all expressinos together and invoke:
// var q4 = Queryable.SelectMany(db.A, a => q3.Where(x => x.a == a).Select(x => x.b), (a, b) => new { a, b });
var paramTuple3 = Expression.Parameter(tuple2);
var paramTuple4 = Expression.Parameter(tuple2);
var paramOuter3 = Expression.Parameter(typeof(TOuter));
var selectManyResult2 = selectMany
.MakeGenericMethod(
typeof(TOuter),
typeof(TInner),
typeof(TResult)
)
.Invoke(
null,
new object[]
{
outer,
Expression.Lambda(
Expression.Convert(
Expression.Call(
null,
select.MakeGenericMethod(tuple2, typeof(TInner)),
new Expression[]
{
Expression.Call(
null,
where.MakeGenericMethod(tuple2),
new Expression[]
{
selectMany1Result,
Expression.Lambda(
Expression.Equal(
paramOuter3,
Expression.MakeMemberAccess(paramTuple4, paramTuple4.Type.GetProperty("Item1"))
),
paramTuple4
)
}
),
Expression.Lambda(
Expression.MakeMemberAccess(paramTuple3, paramTuple3.Type.GetProperty("Item2")),
paramTuple3
)
}
),
typeof(IEnumerable<TInner>)
),
paramOuter3
),
resultSelector
}
); return (IQueryable<TResult>)selectManyResult2;
}

EF INNER JOIN,LEFT JOIN,GROUP JOIN的更多相关文章

  1. EF 里的 join and Group Join

    join ); pageCount = _db.Orders.Count(); return _db.Orders.OrderByDescending(c=>c.ID).Skip(skip).T ...

  2. Linq中join & group join & left join 的用法

    Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报  分类: C#(14)  文章 ...

  3. Join, Group Join

    Linq的 Join对应SQL中的inner join,当左右两张表有匹配数据时才返回一条记录: Linq的 Group Join对应SQL中的LEFT OUTER JOIN,即使右表中没有匹配,也从 ...

  4. Linq表连接大全(INNER JOIN、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、CROSS JOIN)

    我们知道在SQL中一共有五种JOIN操作:INNER JOIN.LEFT OUTER JOIN.RIGHT OUTER JOIN.FULL OUTER JOIN.CROSS JOIN 1>先创建 ...

  5. Merge join、Hash join、Nested loop join对比分析

    简介 我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge Join,Hash Join ...

  6. join中级篇---------hash join & merge join & nested loop Join

    嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: ...

  7. 1122MySQL性能优化之 Nested Loop Join和Block Nested-Loop Join(BNL)

    转自http://blog.itpub.net/22664653/viewspace-1692317/ 一 介绍  相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说 ...

  8. SQL JOIN\SQL INNER JOIN 关键字\SQL LEFT JOIN 关键字\SQL RIGHT JOIN 关键字\SQL FULL JOIN 关键字

    SQL join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据. Join 和 Key 有时为了得到完整的结果,我们需要从两个或更多的表中获取结果.我们就需要执行 join. 数据库中的表 ...

  9. hadoop 多表join:Map side join及Reduce side join范例

    最近在准备抽取数据的工作.有一个id集合200多M,要从另一个500GB的数据集合中抽取出所有id集合中包含的数据集.id数据集合中每一个行就是一个id的字符串(Reduce side join要在每 ...

随机推荐

  1. sprint2总结

    在sprint第二阶段的学习过程中,前期和后期在学校网络的支持下我们成功的延迟了把代码上传github的时间,在我们自己感觉上看,完成项目的质量比较理想,在经过sprint第一阶段的学习后,部分上的问 ...

  2. iphone状态栏高度?

      设备分辨率         状态栏高度           导航栏高度 标签栏高度 iPhone6 plus       1242×2208 px           60px           ...

  3. WP8.1 C#代码 添加/获取Grid.ColumnDefinitions/RowDefinitions

    WP8.1: ColumnDefinitions和RowDefinitions的道理是相同的,语法顺序是一样的,只不过是将ColumnDefinitions换成RowDefinitions而已 获取并 ...

  4. gulp任务

    项目使用的gulp自动化任务 //定义输出文件夹名称 var distFolderH5 = "distH5"; var distFolderMofang = "distM ...

  5. Python之路----------shutil模块

    高级的文件.文件夹.压缩包 处理模块 复制文件: import shutil f1 = open('test') f2 = open('test2','w') shutil.copyfileobj(f ...

  6. Java实现插入排序

    package Sort; import java.util.Arrays; public class InsertionSort { public static int[] sort(int[] l ...

  7. 使用Microsoft Fakes隔离测试代码

    在单元测试(Unit Test)中我们遇到的问题之一是:假如被测试组件(类或项目)为A,组件A依赖于组件B,那么在组件A的单元测试ATest中测试A时,也需要依赖于B,在B发生改动后,就可能影响到A的 ...

  8. OpenXml Sdk 根据Word模板导出到word

    一:OpenXml Sdk 简介 Open XML标准的简单介绍:Ecma Office Open XML(“Open XML”)是针对字处理文档.演示文稿和电子表格的国际化开放标准,可免费供多个应用 ...

  9. MVC之权限管理-网站开发之路

    一.前言 刚到公司没多长时间就开始接触MVC到现在不能说懂了,只能说到达会用这个层次吧,感觉MVC用来写Web还是很强大的,层次清晰. 今天我来写写关于权限管理这一块,自我感觉网站的权限主要分为菜单权 ...

  10. JSP基本语法小结

    jsp表达式:<%=???%> 在jsp页面嵌入java代码<%Java代码%>可以用多个<% %>分割代码段 jsp声明:<%!用这样的方法可以声明java ...