前面我们总结Linq查询子句总共有8个,join子句是我们讲解的最后一个子句。join子句也是相对比较复杂的,所以最后来讲。join子句可以处理两个数据源之间的联系,当然这两个数据源之间必须存在相关联的值。
join子句可以实现3中连接关系
1.内部联接:元素的联接关系必须同时满足被连接的两个数据源
2.分组联接:含有into子句的join子句
3.左外部联接
下面我们就详细的分析一下这三种联接方式。
准备数据:
除了前面用到的UserBaseInfo类,我们新增一个roles类:
1 using System; 2 using System.Data; 3 using System.Configuration; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Security; 7 using System.Web.UI; 8 using System.Web.UI.HtmlControls; 9 using System.Web.UI.WebControls; 10 using System.Web.UI.WebControls.WebParts; 11 using System.Xml.Linq; 12 using System.Collections; 13 using System.Collections.Generic; 14 15 namespace LinqQueryDemo 16 { 17 /// <summary> 18 /// 角色的基本信息 19 /// </summary> 20 public class RoleInfo 21 { 22 private int id; 23 private string roleName; 24 25 /// <summary> 26 /// 角色的ID值 27 /// </summary> 28 public int ID 29 { 30 get { return id; } 31 set { id = value; } 32 } 33 /// <summary> 34 /// 角色的名称 35 /// </summary> 36 public string RoleName 37 { 38 get { return roleName; } 39 set { roleName = value; } 40 } 41 42 public RoleInfo(int id, string roleName) 43 { 44 this.id = id; 45 this.roleName = roleName; 46 } 47 } 48 }
内部联接
内部联接和sqlserver中的inner join类似,联接关系必须同时满足两个被联接的数据源。下面代码中的InnerJoinQuery方法演示了内部联接users和roles数据源的查询方法。
1 private void InnerJoinQuery() 2 { 3 4 List<UserBaseInfo> users = new List<UserBaseInfo>(); 5 List<RoleInfo> roles = new List<RoleInfo>(); 6 7 8 for (int i = 1; i < 10; i++) 9 { 10 users.Add(new UserBaseInfo(i, "users0" + i.ToString(), "user0" + i.ToString() + "@web.com", i * 2)); 11 roles.Add(new RoleInfo(i, "RoleName0" + i.ToString())); 12 } 13 14 //查询ID值小于9,且角色包含roles中的用户 15 var result = from u in users 16 join r in roles on u.RoleId equals r.ID 17 18 where u.ID < 9 19 select u; 20 21 foreach (var u in result) 22 { 23 24 Response.Write(u.UserName + "</br>"); 25 26 } 27 }
查询结果:
分组联接
含有into子句的join子句被分组连接。分组联接产生分层数据结构。它将第一个集合中的每个元素与第二个集合中的元素进行匹配,在查询结果中,第一个集合中的元素都会出现,第二个集合中的元素如果匹配成功,则使用被找到的元素否则为空。
下面的groupjoinquery函数演示分组联接。
1 private void GroupJoinQuery() 2 { 3 4 List<UserBaseInfo> users = new List<UserBaseInfo>(); 5 List<RoleInfo> roles = new List<RoleInfo>(); 6 7 8 for (int i = 1; i < 10; i++) 9 { 10 users.Add(new UserBaseInfo(i, "users0" + i.ToString(), "user0" + i.ToString() + "@web.com", i * 2)); 11 roles.Add(new RoleInfo(i, "RoleName0" + i.ToString())); 12 } 13 14 //查询ID值小于9,且角色包含roles中的用户 15 var result = from u in users 16 join r in roles on u.RoleId equals r.ID into g 17 18 where u.ID < 9 19 select new 20 { 21 ID = u.ID, 22 UserName = u.UserName, 23 Email = u.Email, 24 RoleId = u.RoleId, 25 Roles = g.ToList() 26 }; 27 foreach (var u in result) 28 { 29 30 Response.Write(u.UserName +","+(u.Roles.Count>0?u.Roles[0].RoleName:string.Empty)+ "</br>"); 31 32 } 33 }
查询结果:
左外部联接
左外部联接跟sqlserver中的left join相似。他返回第一个集合中的所有元素,第二个集合中与第一个集合相关的元素显示。如果第二个集合中没有找到相关的元素,就用DefaultEmpty方法来指定默认值。
1 private void LeftOuterJoinQuery() 2 { 3 4 List<UserBaseInfo> users = new List<UserBaseInfo>(); 5 List<RoleInfo> roles = new List<RoleInfo>(); 6 7 8 for (int i = 1; i < 10; i++) 9 { 10 users.Add(new UserBaseInfo(i, "users0" + i.ToString(), "user0" + i.ToString() + "@web.com", i * 2)); 11 roles.Add(new RoleInfo(i, "RoleName0" + i.ToString())); 12 } 13 14 //查询ID值小于9,且角色包含roles中的用户 15 var result = from u in users 16 where u.ID < 9 17 join r in roles on u.RoleId equals r.ID into gr 18 from ur in gr.DefaultIfEmpty() 19 select new 20 { 21 ID = u.ID, 22 UserName = u.UserName, 23 Email = u.Email, 24 RoleId = u.RoleId, 25 Roles = gr.ToList() 26 }; 27 foreach (var u in result) 28 { 29 30 Response.Write(u.UserName +","+(u.Roles.Count>0?u.Roles[0].RoleName:string.Empty)+ "</br>"); 31 32 } 33 }
运行结果: