1 linq介紹
1.1 linq產生背景
一個應用服務後臺程式,肯定會需要格式各樣的資料檢索跟操作,而這些資料在過去的這些年裡一般都會包含在關係型資料庫或者xml檔案中。
.Net3.5版本發行之前,傳統的資料來源訪問方式就是直接對資料庫或者xml檔案進行檢索操作。在.Net3.5 Visual Studio 2008版本之後,微軟創新地新增了linq(Language INtegrated Query)語法,也因此增加了一種傳統資訊儲存檢索之外的一種記憶體資料處理機制。
舉個例子,你可以建立1個list,存幾百個整型資料,你可以寫linq表示式,來檢索子集(比如偶數子集,奇數子集等)。
1.2 linq使用範圍
- linq語法統一了對於資料來源的查詢標準,概念,包括關係型資料庫,xml檔案喝記憶體級別的資料結構。你可以用linq同樣的語法,去查詢xml檔案跟關係型資料庫或者記憶體資料結構;
- linq在關係型資料,與物件之間起到了橋樑作用(可通過linq迴圈方法實現);
1.3 linq核心程式集
程式集名稱 | 描述 |
---|---|
System.LINQ | 提供linq查詢的一些類跟介面 |
System.Collections.Generic | 允許使用者建立泛型集合以保證更好的型別安全與效能 |
System.Data.LINQ | 提供了用linq來訪問關係型資料庫的功能(LINQ TO SQL) |
System.XML.LINQ | 提供了用linq來訪問XML檔案的功能(LINQ TO XML) |
System.Data.Linq.Mapping | 將類指定為與資料庫關聯的實體類 |
1.4 linq架構圖
-
LINQ to Objects 處理的是記憶體資料,任何類都能實現IEnumerable<T>集合介面(在System.Collections.Generic名稱空間),然後就可以用標準的linq語法進行查詢檢索了。
-
LINQ to ADO.NET 處理外部資料來源,基於ado.Net去連線資料表獲得 IEnumerable<T> or IOueryable<T>(在System.Linq名稱空間)資料,然後就可以使用linq語法進行適配檢索。這一功能在System. Data.Linq 名稱空間實現。
-
LINQ to XML 統一簡化了xml檔案的操作,名稱空間是 System.Xml.Linq。
1.5 linq使用形式對比
1.5.1 linq To Objects
string[] instructors = { "Aaron", "Fritz", "Keith", "Scott" };
IEnumerable<string> query = from n in instructors
where n.Length == 5
orderby n descending
select n.Length;
1.5.2 linq To Xml
XElement instructors = XElement.Parse(
@"<instructors>
<instructor>Aaron</instructor>
<instructor>Fritz</instructor>
<instructor>Keith</instructor>
<instructor>Scott</instructor>
</instructors>"
);
IEnumerable<string> query = from n in instructors.Elements("instructor")
where n.Value.Length == 5
orderby n.Value descending
select n.Value;
foreach (string name in query)
{
Console.WriteLine(name);
}
1.5.3 linq To Sql
類定義
[Table(Name = "dbo.Customers")]
public partial class Customer
{
[Column(IsPrimaryKey = true)]
public string CustomerID
{
get
{
return this._CustomerID;
}
set
{
if ((this._CustomerID != value))
{
this._CustomerID = value;
}
}
}
private string _CustomerID;
[Column]
public string CompanyName
{
get
{
return this._CompanyName;
}
set
{
if ((this._CompanyName != value))
{
this._CompanyName = value;
}
}
}
// ... and so on
}
linq語法
IEnumerable<Customer> customers =
from c in context.Customers
where c.Country == "France"
orderby c.CustomerID ascending
select c;
foreach (Customer c in customers)
{
Console.WriteLine(c.CustomerID);
}
1.5.4 LINQ to DataSets
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT * FROM Customers",
_connectionString);
DataTable customers = new DataTable("customers");
adapter.Fill(customers);
int countOfFrenchCustomers =
(from c in customers.AsEnumerable()
where c.Field<string>("Country") == "France"
select c).Count();
1.5.5 小結
以上可看出,linq語法規範形式統一,不同的核心庫會有一些基元元素的不同方法。使用語法一致。
備註:工作原因,本文後續將詳細介紹記憶體資料結構進行程式碼示例,xml檔案與關係型資料庫只做形式上的比較,不作驗證,讀者感興趣的可自行深入研究
2.linq To Objects實際應用兩例
2.1左聯與內聯
2.1.1 本質區別
- 左聯即使右表為空還是能顯示左表;內聯如果右表為空,左表不顯示;
2.1.2 左聯應用
2.1.2.1 程式示例
//刪除ipbox表資料
dbContent.IPBox.RemoveRange(_ipboxDBList);
//AIC表資料
var aics = (from a in _ipboxDBList
join b in dbContent.Aic.AsNoTracking() on a.Id equals b.ParentID
select new Aic
{
ParentID = a.Id,
Id = b.Id
}).ToList();
if (aics != null) { dbContent.Aic.RemoveRange(aics); }
2.1.2.2 程式解釋
ipbox是裝置箱表,aic是ipbox的一個採集屬性,是ipbox的子表,前者與後者是1對多的關係。ipbox必然存在情況下,aic不一定存在。
2.1.2.3 左聯內聯比對
如果此時採用左聯方式,ipbox存在記錄的條件下,對應的aic不存在,但卻也能檢索出資料,只是aic的id為空,parentId(ipbox的id)卻有值。去aic表裡刪除,缺少對應記錄,缺少主鍵,資料庫就會丟擲異常。
此時採用內聯方式,aic如果不存在,則沒有記錄,異常問題解決。
2.1.3 內聯應用
2.1.3.1 程式示例
//關聯裝置箱艙門許可權查詢,返回分頁列表
var list = (from c in DataList
join i in _dbContent.IPBox on c.IpboxId equals i.Id
join a in _dbContent.Area on i.AreaID equals a.Id
join manu in _dbContent.Manufacturer on c.ManufId equals manu.Id
join role in _dbContent.IPBoxCabinRule.Where(b => b.UserId.ToString() == UserId) on i.Id equals role.IpboxId
//採用左聯方式刪除型號時,就不會篩選不出攝像頭
join model in _dbContent.CameraModel on c.ModelId equals model.Id
into temp from info in temp.DefaultIfEmpty(new CameraModel { Id=0,Code=null})
select new CameraViewModel
{
Id = c.Id,
Code = c.Code,
Name = c.Name,
Ip = c.Ip,
rtuId = c.rtuId,
Status = c.Status,
InstallTime = c.InstallTime,
UserName = c.UserName,
Password = c.Password,
rtspurl = c.rtspurl,
OperCompanyId = c.OperCompanyId,
OperCompanyName = c.OperCompanyName,
Enable = c.Enable,
Remark = c.Remark,
Type = c.Type,
CameraType = c.CameraType,
OutputChannel = c.OutputChannel,
AreaName = a.AreaName,
AreaId = i.AreaID,
CameraModelCode = info.Code,
CameraModelId = info.Id ,
ManufacturerName = manu.Name,
ManufacturerId = manu.Id,
IpboxName = i.IPBoxName,
IpboxId = i.Id,
OperPersonId = c.OperPersonId,
OperPersonName = c.OperPersonName,
CreateTime = c.CreateTime
}).ToList();
2.1.3.2 程式解釋
攝像頭表DataList,與其關聯表CameraModel,進行左聯,返回資料給前端作列表展示。
2.1.3.3 左聯內聯比對
如果此時採用內聯方式,刪除攝像頭型號的時候,攝像頭記錄存在就不能被有效檢索出來。
因此此處應採用左聯方式,即使攝像頭型號為空,攝像頭記錄依然能返回。
2.1.3.4 左聯內聯程式碼比較
- 左聯程式碼如下,大意為,如果有資料放入temp,如果為空則new CameraModel { Id=0,Code=null},因此不會影響dataList有效記錄的返回。
//採用左聯方式刪除型號時,就不會篩選不出攝像頭
join model in _dbContent.CameraModel on c.ModelId equals model.Id
into temp from info in temp.DefaultIfEmpty(new CameraModel { Id=0,Code=null})
- 內聯程式碼,比較的簡單粗暴,但是如果攝像頭型號被刪除,則攝像頭本身記錄也無法被檢索出來。
join model in _dbContent.CameraModel on c.ModelId equals model.Id
2.2 linq迴圈方法
2.2.1 程式程式碼
// linq方法語法:
AreaViewModeList.ForEach(m =>
{
var Temp = _areaList.FirstOrDefault(n => n.Id == m.areaCode);
if (Temp != null)
{
m.areaName = Temp.AreaName;
}
}
2.2.2 程式碼應用場景
_areaList是區域表包含了區域類,該類內的欄位areaCode與AreaName的關係是一一對應的字典表關係。而AreaViewModeList裡的每個例項需要根據_areaList例項的areaCode來檢索出對應的AreaName並且賦值給AreaViewModeList裡的每個例項的AreaName欄位。
2.2.3 小結
linq在關係型資料,與物件之間起到了橋樑作用。
3.總結
以上是我對linq的基本介紹,與工作中遇到linq的總結。linq的使用需要在工作中不斷思考與總結,融匯貫通,他能在記憶體列表級資料處理上發揮大作用。
參考網站:
Using LINQ With C#
Introduction To LINQ
版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。