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. Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享

    Nginx+Tomcat+Redis实现负载均衡.资源分离.session共享 CentOS安装Nginx http://centoscn.com/CentosServer/www/2013/0910 ...

  2. libgdx 裁剪多边形(clip polygon、masking polygon)

    直接放例子代码,代码中以任意四边形为例,如果需要做任意多边形,注意libgdx不能直接用ShapeRender填充多边形,需要先切割成三角形. public static void drawClip( ...

  3. System.Data.SqlClient.SqlException: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: SQL Network Interfaces, error: 26 - 定位指定的服务器/实例时出错)

    A network-related or instance-specific error occurred while establishing a connection to SQL Server. ...

  4. xmpp openfire smack 介绍和openfire安装及使用

    前言 Java领域的即时通信的解决方案可以考虑openfire+spark+smack.当然也有其他的选择. Openfire是基于Jabber协议(XMPP)实现的即时通信服务器端版本,目前建议使用 ...

  5. 搜索引擎Solr系列(一): Solr6.2.1环境搭建

     一:Solr简介 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引:也可以通 ...

  6. DNS 中的协议字段详细定义

    DNS中的协议字段定义 Table of Contents 1 概述 2 DNS Classes 3 DNS OpCodes 4 DNS RCODEs 5 DNS Label Types 6 DNS资 ...

  7. 使用Visual Studio扩展插件Visual assist X给代码插入注释模板

    Visual Assist 是由Whole Tomato公司为Microsoft Visual Studio开发的一款插件.它对Visual Studio的智能提示功能和代码高亮功能进行了增强,同时还 ...

  8. HDU 5047 Sawtooth(大数优化+递推公式)

    http://acm.hdu.edu.cn/showproblem.php?pid=5047 题目大意: 给n条样子像“m”的折线,求它们能把二维平面分成的面最多是多少. 解题思路: 我们发现直线1条 ...

  9. XPath 运算符

    XPath 表达式可返回节点集.字符串.逻辑值以及数字. XPath 运算符 下面列出了可用在 XPath 表达式中的运算符: 运算符 描述 实例 返回值 | 计算两个节点集 //book | //c ...

  10. Android 自定义 view(四)—— onMeasure 方法理解

    前言: 前面我们已经学过<Android 自定义 view(三)-- onDraw 方法理解>,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法 推荐文章: htt ...