LINQ左连接和右连接

LINQ Left Join And Right Join

我需要帮助,

我有两个名为a和b的数据表,我需要a的所有行和b的匹配行

前任:

1
2
3
4
5
6
A:                                           B:

User | age| Data                            ID  | age|Growth                                
1    |2   |43.5                             1   |2   |46.5
2    |3   |44.5                             1   |5   |49.5
3    |4   |45.6                             1   |6   |48.5

我需要输出:

1
2
3
4
5
User | age| Data |Growth
------------------------                          
1    |2   |43.5  |46.5                          
2    |3   |44.5  |                          
3    |4   |45.6  |

您提供的示例数据和输出并不演示左联接。如果是左连接,您的输出将如下所示(请注意,对于用户1,我们有3个结果,即,对于用户1拥有的每个增长记录,我们有一个结果):

1
2
3
4
5
6
7
User | age| Data |Growth
------------------------                          
1    |2   |43.5  |46.5                          
1    |2   |43.5  |49.5    
1    |2   |43.5  |48.5    
2    |3   |44.5  |                          
3    |4   |45.6  |

假设您仍然需要一个左联接;下面介绍如何在LINQ中执行左联接:

1
2
3
4
5
6
7
8
9
var results = from data in userData
              join growth in userGrowth
              on data.User equals growth.User into joined
              from j in joined.DefaultIfEmpty()
              select new
              {
                  UserData = data,
                  UserGrowth = j
              };

如果要进行正确的联接,只需交换要从上方选择的表,如下所示:

1
2
3
4
5
6
7
8
9
var results = from growth in userGrowth
              join data in userData
              on growth.User equals data.User into joined
              from j in joined.DefaultIfEmpty()
              select new
              {
                  UserData = j,
                  UserGrowth = growth
              };

代码的重要部分是into语句,后面是defaultifempty。这告诉Linq,如果另一个表中没有匹配的结果,我们希望有默认值(即空值)。


琼斯医生显示左外联接,但正确的答案会略有不同-因为在最初的问题中,两个表在年龄字段上链接,以便根据需要获得准确的结果,应使用以下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
....
//ctx = dataContext class - not shown here.
var user1 = new UserData() { User = 1, Age = 2, Data = 43.5 };
var user2 = new UserData() { User = 2, Age = 3, Data = 44.5 };
var user3 = new UserData() { User = 3, Age = 4, Data = 45.6 };

ctx.UserData.AddRange(new List<UserData> { user1, user2, user3 });

var growth1 = new UserGrowth() { Id = 1, Age = 2, Growth = 46.5 };
var growth2 = new UserGrowth() { Id = 1, Age = 5, Growth = 49.5 };
var growth3 = new UserGrowth() { Id = 1, Age = 6, Growth = 48.5 };

ctx.UserGrowth.AddRange(new List<UserGrowth> { growth1, growth2, growth3 });

var query = from userData in ctx.UserData
                        join userGrowth in ctx.UserGrowth on userData.Age equals userGrowth.Age
                            into joinGroup
                        from gr in joinGroup.DefaultIfEmpty()
                        select new
                        {
                            User = userData.User,
                            age = userData.Age,
                            Data = (double?)userData.Data,
                            Growth = (double?)gr.Growth
                        };

Console.WriteLine("{0} | {1} | {2} | {3}","User","age","Data","Growth");
            foreach (var x in query)
            {
                Console.WriteLine("{0} | {1} | {2} | {3}", x.User, x.age, x.Data, x.Growth);
            }


.... with following entity classes:

public class UserData
    {
        [Key]
        public int User { get; set; }
        public int Age { get; set; }
        public double Data { get; set; }
    }

    public class UserGrowth
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public double Growth { get; set; }
    }


简单实例

模型

1
2
3
4
5
6
7
8
9
10
11
12
class Employee
    {
        public string Name { get; set; }
        public int ID { get; set; }
        public int ProjectID { get; set; }
    }

    class Project
    {
        public int ProjectID { get; set; }
        public string ProjectName { get; set; }
    }

方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public void leftrighjoin(){
               Project P1 = new Project() { ProjectID = 1, ProjectName ="UID" };
                Project P2 = new Project() { ProjectID = 2, ProjectName ="RBS" };
                Project P3 = new Project() { ProjectID = 3, ProjectName ="XYZ" };
                // Employee List
                List<Employee> ListOfEmployees = new List<Employee>();
                ListOfEmployees.AddRange((new Employee[]
                {
                    new Employee() { ID = 1, Name ="Sunil",  ProjectID = 1 },
                    new Employee() { ID = 1, Name ="Anil", ProjectID = 1 },
                    new Employee() { ID = 1, Name ="Suman", ProjectID = 2 },
                    new Employee() { ID = 1, Name ="Ajay", ProjectID = 3 },
                    new Employee() { ID = 1, Name ="Jimmy", ProjectID = 4 }}));

                //Project List
                List<Project> ListOfProject = new List<Project>();
                ListOfProject.AddRange(new Project[] { P1, P2, P3 });

                //Left join
                var Ljoin = from emp in ListOfEmployees
                            join proj in ListOfProject
                               on emp.ProjectID equals proj.ProjectID into JoinedEmpDept
                            from proj in JoinedEmpDept.DefaultIfEmpty()
                               select new
                               {
                                   EmployeeName = emp.Name,
                                   ProjectName = proj != null ? proj.ProjectName : null
                               };

                //Right outer join
                var RJoin = from proj in ListOfProject
                                join employee in ListOfEmployees
                                on proj.ProjectID equals employee.ProjectID into joinDeptEmp
                                from employee in joinDeptEmp.DefaultIfEmpty()
                                select new
                                {
                                    EmployeeName = employee != null ? employee.Name : null,
                                    ProjectName = proj.ProjectName
                                };

                //Printing result of left join
                Console.WriteLine(string.Join("
", Ljoin.Select(emp =>" Employee Name =" +
    emp.EmployeeName +", Project Name =" + emp.ProjectName).ToArray<string>()));

                //printing result of right outer join
                Console.WriteLine(string.Join("
", RJoin.Select(emp =>" Employee Name =" +
    emp.EmployeeName +", Project Name =" + emp.ProjectName).ToArray<string>()));
}

简单的方法是使用let关键字。这对我有用。

1
2
3
4
5
6
7
8
9
from AItem in Db.A
Let BItem = Db.B.Where(x => x.id == AItem.id ).FirstOrDefault()
Where SomeCondition
Select new YourViewModel
{
    X1 = AItem.a,
    X2 = AItem.b,
    X3 = BItem.c
}

这是对左连接的模拟。如果B表中的每个项与某个项不匹配,则b item返回空值