C# Linq中的outer join

栏目: ASP.NET · 发布时间: 6年前

内容简介:昨天用EF查数据库,遇到了个很奇怪的问题。linq里并没有left join关键字,也没有LeftJoin的方法,所有join默认都是inner join。那么如果我们想以左为基,不管右侧是否存在都可以查询出一条记录,应该怎么做的?建数据库太麻烦,这里咱么用集合代替,但是具体写法是一样的。首先是租客类

昨天用EF查数据库,遇到了个很奇怪的问题。linq里并没有left join关键字,也没有LeftJoin的方法,所有join默认都是inner join。那么如果我们想以左为基,不管右侧是否存在都可以查询出一条记录,应该怎么做的?

建数据库太麻烦,这里咱么用集合代替,但是具体写法是一样的。

首先是租客类

public class People
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int HouseId { get; set; }
}

然后是房屋类

public class House
{
    public int Id { get; set; }
    public string Name { get; set; }
}

然后是Service

public class Service
{
    public IEnumerable<People> People => GetAllPeople();
    public IEnumerable<House> Houses => GetAllHouse();

    private IEnumerable<People> GetAllPeople()
    {
        var list = new List<People>();

        list.Add(new People() { Id = 1, Name = "张三", HouseId = 0 });
        list.Add(new People() { Id = 2, Name = "李四", HouseId = 1 });
        list.Add(new People() { Id = 3, Name = "王五", HouseId = 2 });
        list.Add(new People() { Id = 4, Name = "赵六", HouseId = 3 });
        list.Add(new People() { Id = 5, Name = "孙七", HouseId = 4 });
        list.Add(new People() { Id = 6, Name = "周八", HouseId = 0 });
        list.Add(new People() { Id = 7, Name = "吴九", HouseId = 0 });
        list.Add(new People() { Id = 8, Name = "郑十", HouseId = 0 });

        return list;
    }
  
    private IEnumerable<House> GetAllHouse()
    {
        var list = new List<House>();

        for (int i = 1; i < 9; i++)
        {
            list.Add(new House() { Id = i, Name = i + "号公寓" });
        }

        return list;
    }
}

万事俱备,接下来开始正题:

var innerjoin = from people in service.People
                join house in service.Houses
                on people.HouseId equals house.Id
                select new { people.Id, people.Name, HouseName = house.Name };

foreach(var item in innerjoin)
{
    Console.WriteLine($"{item.Id} {item.Name} {item.HouseName}");
}

输出结果是这样婶儿的:

2 李四 1号公寓
3 王五 2号公寓
4 赵六 3号公寓
5 孙七 4号公寓

然后是重头戏,outer join了。outer join也就是left join(right join在linq里就是左右集合反过来,没有别的办法实现),实现的难点在于让右侧不存在的项,放置一个空即null。

这时候聪明的你开始思考了,为空不就是DefaultIfEmpty()吗,说着随手写出了如下代码:

var innerjoin = from people in service.People
                join house in service.Houses.DefaultIfEmpty()
                on people.HouseId equals house.Id
                select new { people.Id, people.Name, HouseName = house.Name };

结果如何呢?

2 李四 1号公寓
3 王五 2号公寓
4 赵六 3号公寓
5 孙七 4号公寓

???

为什么会这样?

仔细分析就会发现,DefaultIfEmpty()这个方法作用在了service.Houses上,也就是说,只有在我们的service提供的Houses集合为空时,结果才是null,这并不符合我们上面的思路。按照我们的思路,在join右侧的集合的查询结果上调用DefaultIfEmpty()才能生效。

var innerjoin = from people in service.People
                join house in service.Houses
                on people.HouseId equals house.Id
                into tmps
                from tmp in tmps.DefaultIfEmpty()
                select new { people.Id, people.Name, HouseName = tmp.Name };

结果如下:

1 张三
2 李四 1号公寓
3 王五 2号公寓
4 赵六 3号公寓
5 孙七 4号公寓
6 周八
7 吴九
8 郑十

与上面相比,多了个into。那么这个into是什么意思呢?百度百科可以查到: into 关键字表示 将前一个查询的结果视为后续查询的生成器。

光看这么个玩意儿估计也搞不明白他到底什么意思,接下来我提一个方法你就懂上面那一坨linq关键字都是什么意思了(说实在的,linq关键字真的很反直觉)。

我们把这个linq查询语句改成等价的lambda形式,如下:

var innerjoin = service.People.GroupJoin(inner: service.Houses,
                                         outerKeySelector: people => people.HouseId,
                                         innerKeySelector: house => house.Id,
                                         resultSelector: (people, houses) => new { people.Id, people.Name, Houses = houses.DefaultIfEmpty() })
                              .SelectMany(collectionSelector: (c => c.Houses),
                                          resultSelector: (c, house) => new { c.Id, c.Name, HouseName = house == null ? "" : house.Name });

是不是一目了然了。join into语句合在一起,相当于GroupJoin方法,将右表整成一个集合,是双层的,形成一个一对多关系;而单纯的join则是平面的,一对一的。

在houses调用DefaultIfEmpty()方法,可以在houses集合为空时,向里面添加一条值为null的项,这样一来就不会被下一步的SelectMany方法忽略。


以上所述就是小编给大家介绍的《C# Linq中的outer join》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web 2.0 Architectures

Web 2.0 Architectures

Duane Nickull、Dion Hinchcliffe、James Governor / O'Reilly / 2009 / USD 34.99

The "Web 2.0" phenomena has become more pervasive than ever before. It is impacting the very fabric of our society and presents opportunities for those with knowledge. The individuals who understand t......一起来看看 《Web 2.0 Architectures》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具