EF INNER JOIN,LEFT JOIN,GROUP JOIN

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 < 4, 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 });

扩展方法

        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 == 3)
                .OrderBy(x => x.ToString().Length)
                .ToList();
            var selectMany = selectManies.First();
            var select = typeof(Queryable).GetMethods().First(x => x.Name == "Select" && x.GetParameters().Length == 2);
            var where = typeof(Queryable).GetMethods().First(x => x.Name == "Where" && x.GetParameters().Length == 2);
            var groupJoin = typeof(Queryable).GetMethods().First(x => x.Name == "GroupJoin" && x.GetParameters().Length == 5);
            var defaultIfEmpty = typeof(Queryable).GetMethods().First(x => x.Name == "DefaultIfEmpty" && x.GetParameters().Length == 1);

            // 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;
        }
时间: 2024-10-07 09:48:57

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

Linq中join &amp; group join &amp; left join 的用法

Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报  分类: C#(14)  文章转自:http://www.cnblogs.com/c-jquery-linq-sql-net-problem/archive/2011/01/17/LINQ_Inner_Join_Group_Join_Left_Join.html 我们在做SQL查询的时候经常会用到Inner Join,Left Join,

第四十回 EF架构~LinqToEntity里实现left join的一对一与一对多

回到目录 对于linq to sql里实现left join我已经介绍过了,这篇文章的出现是由于最近在项目里遇到的一个问题,解决这个问题花了我不少时间,可能有2个小时,事件是这样的,对于两个表,它们是一对多关系,而需求是返回一个一对一的关系,并将最新的数据返回,这个很多同学都知道,可以使用inner join,但是,对于inner  join来说,当处理的是一对多关系时,它将会出现多条记录,这也是正常的:而它并不满足我们今天的需求,经过测试后,找到了解决这个问题的方法,下面看代码: 一对多关系

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

转载http://www.cnblogs.com/shenqiboy/p/3260105.html 我们知道在SQL中一共有五种JOIN操作:INNER JOIN.LEFT OUTER JOIN.RIGHT OUTER JOIN.FULL OUTER JOIN.CROSS JOIN        内连接.Sql: SELECT [t0].[GroupName], [t1].[UserName] FROM [Group] AS [t0] INNER JOIN [User] AS [t1] ON (

join中级篇---------hash join &amp; merge join &amp; nested loop Join

嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: 图1.循环嵌套连接的第一步 图2.循环嵌套连接的第二步 由上面两个图不难看出,循环嵌套连接查找内部循环表的次数等于外部循环的行数,当外部循环没有更多的行时,循环嵌套结束.另外,还 可以看出,这种连接方式需要内部循环的表有序(也就是有索引),并且外部循环表的行数要小于内部循环的行数,否则查询分析器就

SQL Tuning 基础概述06 - 表的连接方式:Nested Loops Join,Merge Sort Join &amp; Hash Join

nested loops join 嵌套循环 merge sort join 排序合并 hash join 哈希连接 nested loops join(嵌套循环)   驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_nl() merge sort join(排序合并)   驱动表和被驱动表都是最多访问1次,无驱动顺序,需要排序(SORT_AREA_SIZE),连接条件是<>或like导致无法使用

oracle--left join and 和left join where的区别

开发程序时,经常会遇到left join,inner join的语句,Join是关系型数据库系统的重要操作之一,相对来说速度要快一些,所以大家一般都会优先选择join语句. 但是在做程序时,对于join的一些用法却不一定很清晰.今天给大家讲的是left join and 和left join where. ?数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion on时,and和where条件的区别如下: 1. on条件是在生

SQL SERVER 2012 第四章 连接 JOIN の OUTER JOIN,完全连接FULL JOIN,交叉连接CROSS JOIN

SELECT <SELECT LIST> FROM <the table you want to be the "LEFT" table> <LEFT|RIGHT> [OUTER] JOIN <table you want to be the "RIGHT" table> ON <join condition> 可以看做JOIN之前的表是左表,之后的表是右表. 外部连接本质上是包含的.明确包含的记录取决于使

深入理解Oracle表(3):三大表连接方式详解之Nested loop join和 Sort merge join

深入理解Oracle表(3):三大表连接方式详解之Nested loop join和 Sort merge join 分类: Oracle 基础管理 Oracle SQL 开发2013-01-28 00:33 2536人阅读 评论(1) 收藏 举报 关系数据库技术的精髓就是通过关系表进行规范化的数据存储       并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理       这里Think愿意和大家一起来学习分享Oracle的三大表连接技术              在早期版本,

一步一步跟我学习lucene(18)---lucene索引时join和查询时join使用示例

了解sql的朋友都知道,我们在查询的时候可以采用join查询,即对有一定关联关系的对象进行联合查询来对多维的数据进行整理.这个联合查询的方式挺方便的,跟我们现实生活中的托人找关系类似,我们想要完成一件事,先找自己的熟人,然后通过熟人在一次找到其他,最终通过这种手段找到想要联系到的人.有点类似于"世间万物皆有联系"的感觉. lucene的join包提供了索引时join和查询时join的功能: Index-time join 大意是索引时join提供了查询时join的支持,且IndexWr