網(wǎng)站首頁 編程語言 正文
linq中的連接操作符主要包括Join()和GroupJoin()兩個。
一、Join()操作符
Join()操作符非常類似于T-SQL中的inner join,它將兩個數(shù)據(jù)源進行連接,根據(jù)兩個數(shù)據(jù)源中相等的值進行匹配。例如:可以將產(chǎn)品表和產(chǎn)品類別表進行連接,得到產(chǎn)品名稱和與其對應(yīng)的類型名稱。下面看看Join()方法的定義:
public static IEnumerableJoin (this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector); public static IEnumerable Join (this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer comparer);
從Join()方法的定義中可以看到:Join操作符的方法原型非常復(fù)雜,從方法原型可以看到,參數(shù)outer和inner是需要連接的兩個輸入集合。其中outer代表的是調(diào)用的集合。當(dāng)Join操作符被調(diào)用時,首先列舉inner序列中的所有元素,為序列中每一個類型為U的元素調(diào)用委托InnerKeySelector,生成一個類型為K的的對象innerKey作為連接關(guān)鍵字。(相當(dāng)于數(shù)據(jù)庫中的外鍵),將inner序列中的每一個元素和其對應(yīng)的連接關(guān)鍵字innerKey存儲在一個臨時哈希表中;其次列舉outer序列中的所有元素,為每一個類型為T的元素調(diào)用委托outerKeySelector,生成一個類型為K的對象outKey用作連接關(guān)鍵字,在第一步生成的臨時哈希表中查找與outKey相等的對應(yīng)的innerKey對象,如果找到對應(yīng)的記錄,會將當(dāng)前outer序列中的類型為T的元素和對應(yīng)的inner序列中類型為U的元素作為一組參數(shù)傳遞給委托resultSelector,resultSelector會根據(jù)這兩個參數(shù)返回一個類型為V的對象,此類型為V的對象會被添加到Join操作符的輸出結(jié)果序列中去。Join操作符返回一個類型為IEnumerable
1、新建Category和Product兩個類,其類定義分別如下:
Category:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { public class Category { public int Id { get; set; } public string CategoryName { get; set; } public DateTime CreateTime { get; set; } } }
Product:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { public class Product { public int Id { get; set; } public int CategoryId { get; set; } public string Name { get; set; } public double Price { get; set; } public DateTime CreateTime { get; set; } } }
2、在Main()方法中調(diào)用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { class Program { static void Main(string[] args) { // 初始化數(shù)據(jù) ListlistCategory = new List () { new Category(){ Id=1,CategoryName="計算機",CreateTime=DateTime.Now.AddYears(-1)}, new Category(){ Id=2,CategoryName="文學(xué)",CreateTime=DateTime.Now.AddYears(-2)}, new Category(){ Id=3,CategoryName="高校教材",CreateTime=DateTime.Now.AddMonths(-34)}, new Category(){ Id=4,CategoryName="心理學(xué)",CreateTime=DateTime.Now.AddMonths(-34)} }; List listProduct = new List () { new Product(){Id=1,CategoryId=1, Name="C#高級編程第10版", Price=100.67,CreateTime=DateTime.Now}, new Product(){Id=2,CategoryId=1, Name="Redis開發(fā)和運維", Price=69.9,CreateTime=DateTime.Now.AddDays(-19)}, new Product(){Id=3,CategoryId=2, Name="活著", Price=57,CreateTime=DateTime.Now.AddMonths(-3)}, new Product(){Id=4,CategoryId=3, Name="高等數(shù)學(xué)", Price=97,CreateTime=DateTime.Now.AddMonths(-1)}, new Product(){Id=5,CategoryId=6, Name="國家寶藏", Price=52.8,CreateTime=DateTime.Now.AddMonths(-1)} }; // 1、查詢表達式 var queryExpress = from c in listCategory join p in listProduct on c.Id equals p.CategoryId select new { Id = c.Id, CategoryName = c.CategoryName, ProductName = p.Name, PublishTime = p.CreateTime }; Console.WriteLine("查詢表達式輸出:"); foreach (var item in queryExpress) { Console.WriteLine($"id:{item.Id},CategoryName:{item.CategoryName},ProductName:{item.ProductName},PublishTime:{item.PublishTime}"); } Console.WriteLine("方法語法輸出:"); // 方法語法 var queryFun = listCategory.Join(listProduct, c => c.Id, p => p.CategoryId, (c, p) => new { Id = c.Id, CategoryName = c.CategoryName, ProductName = p.Name, PublishTime = p.CreateTime }); foreach (var item in queryFun) { Console.WriteLine($"id:{item.Id},CategoryName:{item.CategoryName},ProductName:{item.ProductName},PublishTime:{item.PublishTime}"); } Console.ReadKey(); } } }
結(jié)果:
從結(jié)果中可以看出:Join()操作符只會輸出兩個結(jié)合中相同的元素,和T-SQL中的inner join類似。
在T-SQL中除了內(nèi)連接以外,還有左連接和右連接,那么使用Join()是不是也可以實現(xiàn)左連接和右連接呢?請看下面的例子。
使用Join()實現(xiàn)左連接。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { class Program { static void Main(string[] args) { // 初始化數(shù)據(jù) ListlistCategory = new List () { new Category(){ Id=1,CategoryName="計算機",CreateTime=DateTime.Now.AddYears(-1)}, new Category(){ Id=2,CategoryName="文學(xué)",CreateTime=DateTime.Now.AddYears(-2)}, new Category(){ Id=3,CategoryName="高校教材",CreateTime=DateTime.Now.AddMonths(-34)}, new Category(){ Id=4,CategoryName="心理學(xué)",CreateTime=DateTime.Now.AddMonths(-34)} }; List listProduct = new List () { new Product(){Id=1,CategoryId=1, Name="C#高級編程第10版", Price=100.67,CreateTime=DateTime.Now}, new Product(){Id=2,CategoryId=1, Name="Redis開發(fā)和運維", Price=69.9,CreateTime=DateTime.Now.AddDays(-19)}, new Product(){Id=3,CategoryId=2, Name="活著", Price=57,CreateTime=DateTime.Now.AddMonths(-3)}, new Product(){Id=4,CategoryId=3, Name="高等數(shù)學(xué)", Price=97,CreateTime=DateTime.Now.AddMonths(-1)}, new Product(){Id=5,CategoryId=6, Name="國家寶藏", Price=52.8,CreateTime=DateTime.Now.AddMonths(-1)} }; // 1、使用查詢表達式實現(xiàn)左連接 var listLeft = from c in listCategory join p in listProduct on c.Id equals p.CategoryId into cpList from cp in cpList.DefaultIfEmpty() select new { Id = c.Id, CategoryName = c.CategoryName, ProductName = cp == null ? "無產(chǎn)品名稱" : cp.Name, PublishTime = cp == null ? "無創(chuàng)建時間" : cp.CreateTime.ToString() }; foreach (var item in listLeft) { Console.WriteLine($"id:{item.Id},CategoryName:{item.CategoryName},ProductName:{item.ProductName},PublishTime:{item.PublishTime}"); } Console.ReadKey(); } } }
結(jié)果:
從結(jié)果中可以看出:左表listCategory中的數(shù)據(jù)全部輸出了,listCategory中分類為4的在listProduct中沒有對應(yīng)的產(chǎn)品記錄,所以該項的ProductName和PublishTime輸出為空。
注意:
在左連接中,有可能右表中沒有對應(yīng)的記錄,所以使用Select投影操作符的時候要注意判斷是否為null,否則程序會報錯,看下面的例子:
使用方法語法實現(xiàn)左連接要使用下面要講的GroupJoin(),所以使用方法語法實現(xiàn)左連接放到GroupJoin()中進行講解。
右連接
其實實現(xiàn)右連接只需要將上面例子中的左表和右邊換一下順序即可。看下面的例子:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { class Program { static void Main(string[] args) { // 初始化數(shù)據(jù) ListlistCategory = new List () { new Category(){ Id=1,CategoryName="計算機",CreateTime=DateTime.Now.AddYears(-1)}, new Category(){ Id=2,CategoryName="文學(xué)",CreateTime=DateTime.Now.AddYears(-2)}, new Category(){ Id=3,CategoryName="高校教材",CreateTime=DateTime.Now.AddMonths(-34)}, new Category(){ Id=4,CategoryName="心理學(xué)",CreateTime=DateTime.Now.AddMonths(-34)} }; List listProduct = new List () { new Product(){Id=1,CategoryId=1, Name="C#高級編程第10版", Price=100.67,CreateTime=DateTime.Now}, new Product(){Id=2,CategoryId=1, Name="Redis開發(fā)和運維", Price=69.9,CreateTime=DateTime.Now.AddDays(-19)}, new Product(){Id=3,CategoryId=2, Name="活著", Price=57,CreateTime=DateTime.Now.AddMonths(-3)}, new Product(){Id=4,CategoryId=3, Name="高等數(shù)學(xué)", Price=97,CreateTime=DateTime.Now.AddMonths(-1)}, new Product(){Id=5,CategoryId=6, Name="國家寶藏", Price=52.8,CreateTime=DateTime.Now.AddMonths(-1)} }; // 使用查詢表達式實現(xiàn)右連接 var listRight = from p in listProduct join c in listCategory on p.CategoryId equals c.Id into pcList from pc in pcList.DefaultIfEmpty() select new { Id = p.Id, CategoryName = pc == null ? "無分類名稱" : pc.CategoryName, ProductName = p.Name, PublishTime = p.CreateTime }; foreach (var item in listRight) { Console.WriteLine($"id:{item.Id},CategoryName:{item.CategoryName},ProductName:{item.ProductName},PublishTime:{item.PublishTime}"); } Console.ReadKey(); } } }
結(jié)果:
從結(jié)果中可以看出:listProduct中的數(shù)據(jù)全部輸出了,listCategory中如果沒有相應(yīng)的記錄就輸出空值。
注意:
在右連接中也需要和左連接一樣進行null值的判斷。
二、GroupJoin()操作符
GroupJoin()操作符常用于返回“主鍵對象-外鍵對象集合”形式的查詢,例如“產(chǎn)品類別-此類別下的所有產(chǎn)品”。
GroupJoin操作符也用于連接兩個輸入序列,但與Join操作符不同稍有不同,Join操作符在列舉outer序列元素時,會將一個outer序列元素和其對應(yīng)的inner序列元素作為一組參數(shù)傳遞給委托resultSelector委托,這就意味著如果某一個outer序列元素有多個對應(yīng)的inner序列元素,Join操作符將會分多次將outer序列元素和每一個對應(yīng)的inner序列元素傳遞給委托resultSelector。使用GroupJoin操作符時,如果某一個outer序列元素有多個對應(yīng)的inner序列元素,那么這多個對應(yīng)的inner序列元素會作用一個序列一次性傳遞給委托resultSelecotr,可以針對此序列添加一些處理邏輯。下面看看GroupJoin()操作符的定義:
public static IEnumerableGroupJoin (this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func , TResult> resultSelector); public static IEnumerable GroupJoin (this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func , TResult> resultSelector, IEqualityComparer comparer);
留意變紅的那個委托,注意,與Join操作符的不同點就是一個outer序列中如果有多個對應(yīng)的inner序列元素,會作為一個集合IEnumerable
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { class Program { static void Main(string[] args) { // 初始化數(shù)據(jù) ListlistCategory = new List () { new Category(){ Id=1,CategoryName="計算機",CreateTime=DateTime.Now.AddYears(-1)}, new Category(){ Id=2,CategoryName="文學(xué)",CreateTime=DateTime.Now.AddYears(-2)}, new Category(){ Id=3,CategoryName="高校教材",CreateTime=DateTime.Now.AddMonths(-34)}, new Category(){ Id=4,CategoryName="心理學(xué)",CreateTime=DateTime.Now.AddMonths(-34)} }; List listProduct = new List () { new Product(){Id=1,CategoryId=1, Name="C#高級編程第10版", Price=100.67,CreateTime=DateTime.Now}, new Product(){Id=2,CategoryId=1, Name="Redis開發(fā)和運維", Price=69.9,CreateTime=DateTime.Now.AddDays(-19)}, new Product(){Id=3,CategoryId=2, Name="活著", Price=57,CreateTime=DateTime.Now.AddMonths(-3)}, new Product(){Id=4,CategoryId=3, Name="高等數(shù)學(xué)", Price=97,CreateTime=DateTime.Now.AddMonths(-1)}, new Product(){Id=5,CategoryId=6, Name="國家寶藏", Price=52.8,CreateTime=DateTime.Now.AddMonths(-1)} }; // 使用GroupJoin()實現(xiàn)左連接 var listLeftFun = listCategory.GroupJoin(listProduct, c => c.Id, p => p.CategoryId, (c, listp) => listp.DefaultIfEmpty(new Product()).Select(z => new { Id = c.Id, CategoryName = c.CategoryName, ProduceName = z.Name, ProductPrice = z.Price })).ToList(); foreach (var item in listLeftFun) { foreach (var p in item) { Console.WriteLine($"CategoryId:{p.Id},CategoryName:{p.CategoryName},ProduceName:{p.ProduceName},ProductPrice:{p.ProductPrice}"); } } Console.ReadKey(); } } }
結(jié)果:
結(jié)果可以看出:使用GroupJoin()操作符可以用Lambda表達式實現(xiàn)左連接。
右連接
只需要調(diào)整上面例子中兩張表的順序即可。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConnectOperation { class Program { static void Main(string[] args) { // 初始化數(shù)據(jù) ListlistCategory = new List () { new Category(){ Id=1,CategoryName="計算機",CreateTime=DateTime.Now.AddYears(-1)}, new Category(){ Id=2,CategoryName="文學(xué)",CreateTime=DateTime.Now.AddYears(-2)}, new Category(){ Id=3,CategoryName="高校教材",CreateTime=DateTime.Now.AddMonths(-34)}, new Category(){ Id=4,CategoryName="心理學(xué)",CreateTime=DateTime.Now.AddMonths(-34)} }; List listProduct = new List () { new Product(){Id=1,CategoryId=1, Name="C#高級編程第10版", Price=100.67,CreateTime=DateTime.Now}, new Product(){Id=2,CategoryId=1, Name="Redis開發(fā)和運維", Price=69.9,CreateTime=DateTime.Now.AddDays(-19)}, new Product(){Id=3,CategoryId=2, Name="活著", Price=57,CreateTime=DateTime.Now.AddMonths(-3)}, new Product(){Id=4,CategoryId=3, Name="高等數(shù)學(xué)", Price=97,CreateTime=DateTime.Now.AddMonths(-1)}, new Product(){Id=5,CategoryId=6, Name="國家寶藏", Price=52.8,CreateTime=DateTime.Now.AddMonths(-1)} }; var listRightFun = listProduct.GroupJoin(listCategory, p => p.CategoryId, c => c.Id, (p, listc) => listc.DefaultIfEmpty(new Category()).Select(z => new { id = p.Id, ProductName = p.Name, ProductPrice = p.Price, CategoreName = z.CategoryName })); foreach (var item in listRightFun) { foreach (var p in item) { Console.WriteLine($"id:{p.id},ProduceName:{p.ProductName},ProductPrice:{p.ProductPrice},CategoryName:{p.CategoreName}"); } } } } }
結(jié)果:
原文鏈接:https://www.cnblogs.com/dotnet261010/p/9308690.html
相關(guān)推薦
- 2023-03-23 一文帶你了解Python中的type,isinstance和issubclass_python
- 2022-08-24 K8S之StatefulSet有狀態(tài)服務(wù)詳解_云其它
- 2022-12-31 C++模擬Linux?Shell編寫一個自定義命令_C 語言
- 2022-08-17 C++詳解Primer文本查詢程序的實現(xiàn)_C 語言
- 2022-11-16 python壓縮和解壓縮模塊之zlib的用法_python
- 2022-12-07 R語言隨機抽樣詳解_R語言
- 2022-12-22 C語言如何使用函數(shù)求素數(shù)和舉例_C 語言
- 2022-11-07 Flink?側(cè)流輸出源碼示例解析_服務(wù)器其它
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支