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. H264编码原理以及I帧、B和P帧详解

    H264是新一代的编码标准,以高压缩高质量和支持多种网络的流媒体传输著称,在编码方面,我理解的他的理论依据是:参照一段时间内图像的统计结果表明,在相邻几幅图像画面中,一般有差别的像素只有10%以内的点 ...

  2. linux 技巧:使用 screen 管理你的远程会话

    你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是不是经常为一些长时间运行的任务而头疼,比如系统备份.ftp 传输等等.通常情况下我们都是为每一个这样的任务开一个远程终 ...

  3. vim - Convert between hex and decimal

    http://vim.wikia.com/wiki/VimTip448 ga g8

  4. gitlab 安装

    GitLab的安装方式 GitLab的两种安装方法: 编译安装 优点:可定制性强.数据库既可以选择MySQL,也可以选择PostgreSQL;服务器既可以选择Apache,也可以选择Nginx. 缺点 ...

  5. error in config file "/etc/rabbitmq/rabbitmq.config"

    记录一次RabbitMQ配置文件配置错误 error信息: dill@ubuntu-vm:/usr/share/doc/rabbitmq-server$ sudo /usr/lib/rabbitmq/ ...

  6. 多节点ssh免密匙登录

    1,在所有节点上,使用yourname用户名执行: ssh-keygen -t dsa -P '' -f /home/yourname/.ssh/id_dsa 2,在node1的/home/yourn ...

  7. oracle 9i相关问题

    Oracle 9i在连接数据库的时候需要加上双引号,如sqlplus “sys/oracle@orcl as sysdba” Oracle 9i不支持bigfile大的表空间创建,oracle9i或以 ...

  8. SP2-0618: 无法找到会话标识符。启用检查 PLUSTRACE 角色 SP2-0611: 启用 STATISTICS 报告时出错

    援引: SP2-0618: 无法找到会话标识符.启用检查 PLUSTRACE 角色 SP2-0611: 启用 STATISTICS 报告时出错 问题描述及解决方法: SQL*Plus: Release ...

  9. getchar的利用

    /*以每行一个单词的形式打印其输入 */ getchar   putchar函数,是逐个打印和输入(逐个循环打印) #include <stdio.h> int main() { int ...

  10. Struts2下载文件点取消出现的异常解决

    struts2点击下载,如果正常下载不会报错,可是如果点击取消就会报如下的错误: Java.lang.IllegalStateException: Cannot call sendError() af ...