LINQ(Language Integrated Query)
Lambda表達式
格式
Lambda表達式比函數有着更為簡潔的語法格式。在某些情況下使用Lamnbda就可以替代函數,讓代碼變得更簡潔易讀。而定義Lambda表達式與定義函數其實差別不大,而且還做到了簡化。
定義函數你得聲明函數的權限修飾符、形態修飾符和參數列表、返回類型等,而Lambda就這么一段代碼就做完了函數的工作
e:參數
=>:操作符,可描述執行后面的邏輯……操作符后面的則是單個表達式,也可以是語句塊。即函數的方法體。
示例
e => e.Name == "sam"; // 隱式聲明了參數 操作符后面是求值表達式
e => { return e.Name == "sam"; } // 隱式聲明了參數 操作符后面是求值語句塊
(string e, string x)=>{ return e.Name == "sam" && e.Age = 32; } //顯示聲明了多參數 操作符后面是求值語句塊
(e, x) => { return e.Name == "sam" && e.Age = 32; } //隱式聲明了多參數 操作符后面是求值語句塊
()=>Console.WriteLine(); //無參數 操作符后面是執行語句 返回void
Lambda與委托
Lambda就是一個匿名的函數,所以你可以將Lambda當成委托實例作為參數進行傳遞,如果要這樣做,則你定義的Lambda表達式的簽名和返回類型必須符合委托的簽名和返回類型
{
Console.WriteLine(d().ToString());
}
static void Main(string[] args)
{
Func<DateTime> getDateTime = () => DateTime.Now; //將匹配Func<T>委托簽名和返回類型的lambda表達式當做委托使用
ShowTime(getDateTime);
}
LINQ延遲查詢機制
LINQ查詢操作符並不會立即執行,它總是在查詢結果集真正被使用的時候才會開啟查詢。 而且每次只將迭代的當前項存入內存中處理,這就降低了內存占用率。那些需要一次性統計所有集合的操作符如:OrderBy、Reverse、ToList、ToArray、ToDictionary,它們都會破壞延遲查詢,也即調用這些操作符則會立即開啟查詢。
var result = numbers.Where(n => n <= 2); //不做任何操作,等待后續調用時才開始執行查詢
foreach (var item in result) //開始linq查詢
Console.WriteLine(item); // print 0,1,2
for (int i = 0; i < 10; ++i) //更改numbers的每個元素,取相反數
numbers[i] = -numbers[i];
foreach (var item in result) //開始linq查詢
Console.WriteLine(item); // print 0,-1,-2,-100
//在這個例子中,如果Where查詢是立即執行的,那么result只會存儲0,1,2,第二次foreach時,也應該輸出0,1,2,但實際情況卻不是這樣
//為什么為linq使用延遲查詢?
//因為上面例子中的numbers只調用了Where方法,如果它不立即開啟查詢,直到你要用到查詢結果的時候才去執行查詢
//那么這樣做的好處是顯而易見,因為在你還未使用查詢結果之前,你可能還會繼續在numbers上調用其它的linq擴展方法
//那么這些擴展方法就形成了一個鏈式的操作
//而這個鏈式操作只返回最終一個結果,省去了每調用一次擴展方法就開啟查詢,無形中就增加了內存或數據庫的查詢壓力
LINQ查詢表達式
LINQ查詢表達式類似於SQL查詢語句,但個人不喜歡它的書寫格式。它是由from、join group by等句子組成的LINQ查詢表達式,而LINQ查詢表達式與直接使用LINQ擴展方法執行查詢在語法結構上是不一樣的,我認為后者更易於閱讀,所以此處略過。
LINQ操作符
幾乎每個Linq操作符都接收一個委托實例(Lambda),操作符對集合進行迭代,每迭代一次會自動調用Lambda,根據lambda來返回結果集。
1.過濾
根據參數提供的lambda表達式指定的邏輯過濾集合中的元素,將計算的結果存入結果集返回。可以按條件、按索引、按開頭或結尾、按唯一的單個項進行篩選。
//根據lambda的邏輯篩選符合條件的元素
//此方法所要求的委托還可以有第三個參數:Index,表示當前對象在集合中的索引號
ElementAt( int index )
//根據參數索引查找處於該索引處的項
Single( [ lambda ] )
//lambda:可選的lambda表達式,用於提供過濾的條件
//返回集合中的唯一的項
//類似的有FirstOrDefault方法,該方法保證無唯一的項時安全返回一個default<T>
//如果集合存在多個項則會引發異常
First( [ lambda ] )
//lambda:可選的lambda表達式,用於提供過濾的條件
//類似的有FirstOrDefault,該方法保證無項時安全返回一個default<T>
//返回集合中的第一個項,或根據過濾獲取指定的項
Last( [ lambda ] )
//lambda:可選的lambda表達式,用於提供過濾的條件
//類似的有LastOrDefault,該方法保證無項時安全返回一個default<T>
//返回集合中的最后一個項,或根據過濾獲取指定的項
2.投影
根據參數提供的lambda表達式返回的項,將項存入結果集返回
//根據lambda表達式的計算邏輯,將計算的結果存入結果集返回
//示例1:
int[] a = { 1, 2, 3 };
var s = a.Select(i => i > 2); //計算i>2的結果,將結果存入結果集返回
foreach (var item in s)
{
Console.WriteLine(item); //print flse,false,true
}
//示例2:
public class Book
{
public string Title { get; set; }
public double Price { get; set; }
public List<Author> Authors { get; set; }
}
public class Author
{
public string Name { get; set; }
}
public class Programe
{
static void Main(string[] args)
{
List<Book> books = new List<Book>
{
new Book
{
Title="寂靜的春天",
Price=19.8,
Authors = new List<Author>
{
new Author{ Name="sam" },
new Author{ Name="leo" }
}
},
new Book
{
Title="萬有引力之虹",
Price=20.7,
Authors=new List<Author>
{
new Author{ Name="korn" },
new Author{ Name="Tim" }
}
},
new Book
{
Title="卡拉馬佐夫兄弟",
Price=30.5,
Authors=new List<Author>
{
new Author{ Name="lily" },
new Author{ Name="lvis" }
}
}
};
IEnumerable<string> titleList = books.Select(book => book.Title); //將lambda表達式的計算結果Book的Title存儲到結果集IEnumerable中,將IEnumerable<string>作為結果集返回
foreach (var title in titleList)
{
Console.WriteLine(title);//print 寂靜的春天,萬有引力之虹,卡拉馬佐夫兄弟
}
IEnumerable<double> priceList = books.Select(book => book.Price); //將lambda表達式的計算結果Book的Price存儲到結果集IEnumerable中,將IEnumerable<double>作為結果集返回
foreach (var price in priceList)
{
Console.WriteLine(price);//print 19.8,20.7,30.5
}
IEnumerable<Book> bookList = books.Select(book => book); //將lambda表達式的計算結果Book存儲到結果集IEnumerable中,將IEnumerable<Book>作為結果集返回
foreach (var book in bookList)
{
Console.WriteLine($"{book.Title}{book.Price}");//print ……
}
IEnumerable<List<Author>> authorListList = books.Select(book => book.Authors); //將lambda表達式的計算結果Book的Authors存儲到IEnumerable中,將 IEnumerable<List<Author>>作為結果集返回
foreach (var authorList in authorListList)
{
foreach (var author in authorList)
{
Console.WriteLine(author.Name); //print sam,leo,korn,Tim,lily,lvis
}
}
}
}
SelectMany ( lambda )
//根據lambda表達式指定的邏輯將計算的結果從集合中抽取出來存入結果集返回
//此方法所要求的委托還可以有第三個參數:Index,表示當前對象在集合中的索引號
//示例:
IEnumerable<Author> authorList = books.SelectMany(book => book.Authors); //將lambda表達式的計算邏輯的結果從集合中抽取出來存入結果集返回,因為Authors是一個List<Author>,抽取Author后存入結果集,所以結果集就是一個 IEnumerable<Author>
3.去重
根據參數提供的lambda表達式返回的項對集合進行去重,將去重后的結果存入結果集返回
//去除集合中的重復項
//comparer:引用類型的去重需要手動為類型實現 IEqualityComparer<T>
//此方法內部維護了一個測試相等性的比較器
//如果項是struct或string,則比較值的相等性
//如果項是class,則比較堆地址的相等性,可是多半在執行查詢時查詢的是class,class多半都是不相等的堆引用,所以此方法無參版只能用於struct或string的去重
Except( IEnumerable < T > second [ , IEqualityComparer < T > comparer ] )
//將參數1的集合與當前集合做比較,返回沒有同時出現在兩個集合中的項。也即求差集
//comparer:可選,引用類型的比較需要手動為類型實現 IEqualityComparer<T>
//此方法內部維護了一個測試相等性的比較器
//如果項是struct或string,則比較值的相等性
//如果項是class,則比較堆地址的相等性,可是多半在執行查詢時查詢的是class,class多半都是不相等的堆引用,所以此方法無參版只能用於struct或string的差集
Intersect( IEnumerable < T > second [ , IEqualityComparer < T > comparer ] )
//將參數1的集合與當前集合做比較,返回同時出現在兩個集合中的項。也即求交集
//comparer:可選,引用類型的比較需要手動為類型實現 IEqualityComparer<T>
//此方法內部維護了一個測試相等性的比較器
//如果項是struct或string,則比較值的相等性
//如果項是class,則比較堆地址的相等性,可是多半在執行查詢時查詢的是class,class多半都是不相等的堆引用,所以此方法無參版只能用於struct或string的交集
Union( IEnumerable < T > second )
//將參數1的集合與當前集合進行合並,也即求並集

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.UI;
using System.IO;
namespace Yin.General
{
public static class LinqHelper<T>
{
public static IEqualityComparer<T> CreateComparer<TV>(Func<T, TV> keySelector)
{
return new CommonEqualityComparer<TV>(keySelector);
}
public static IEqualityComparer<T> CreateComparer<TV>(Func<T, TV> keySelector, IEqualityComparer<TV> comparer)
{
return new CommonEqualityComparer<TV>(keySelector, comparer);
}
private class CommonEqualityComparer<TV> : IEqualityComparer<T>
{
private readonly IEqualityComparer<TV> _comparer;
private readonly Func<T, TV> _keySelector;
public CommonEqualityComparer(Func<T, TV> keySelector, IEqualityComparer<TV> comparer)
{
_keySelector = keySelector;
_comparer = comparer;
}
public CommonEqualityComparer(Func<T, TV> keySelector)
: this(keySelector, EqualityComparer<TV>.Default)
{ }
public bool Equals(T x, T y)
{
return _comparer.Equals(_keySelector(x), _keySelector(y));
}
public int GetHashCode(T obj)
{
return _comparer.GetHashCode(_keySelector(obj));
}
}
}
}
var records = Authors.Distinct(LinqHelper<Author>.CreateComparer<string>(a => a.FirstName)); //根據引用類型Author的FirstName進行去重
4.轉換
//將結果集轉換為數組,不再具有延遲機制,查詢將立即執行
ToList( )
//立即將結果集轉換為列表集合,不再具有延遲機制,查詢將立即執行
ToDictionary( )
//立即將結果集轉換為哈希字典,主要用於將List<T>集合中的元素的某個成員作為哈希字典的key來存取元素,不再具有延遲機制,查詢將立即執行
//示例
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
}
List<Animal> list = new List<Animal>
{
new Animal{ Id=1, Name="sam"},
new Animal{ Id=2, Name="leo"}
};
Dictionary<int, Animal> dictionary = list.ToDictionary( animal => animal.Id ); //用元素的id作為哈希字典的鍵
Console.WriteLine(dictionary[1].Name );
Cast<T>()
//將非泛型集合轉換為泛型集合,非泛型集合沒有Linq查詢,因為存儲的都是object,轉換之后就可以執行linq查詢
AsEnumerable( )
//將結果集轉換為IEnumerable<T>類型,主要用於屏蔽集合的索引器,因為IEnumerable只有一個可迭代的方法,所以如果你只想將集合暴露給用戶查看而不需要他們去設置集合的元素,就可以使用此方法
AsQueryable( )
//將結果集轉換為IQueryable<T>類型
聚合
//所見即所得
Count()
//所見即所得
//ICollection接口有一個Count的屬性
//而擴展方法為集合提供了Count()方法
//兩者都會執行遍歷計算總項數,如果只想測試是否有項,可使用效率更高的Any()
Min()
//所見即所得
Max()
//所見即所得
Average()
//所見即所得
Aggregate()
//所見即所得
6.排序
按lambda表達式返回的項進行排序
//按lambda表達式返回的項進行升序排序,返回一個 IOrderedEnumerable<TSource>
//只能使用一次,如果多次使用了OrderBy方法,那么只有最后一個會生效
//要在一個已經OrderBy的集合上執行再排序應使用ThenBy(),ThenBy()可出現N次
OrderByDescending( lambda [ , IComparer < T > comparer] )
//降序排序
ThenBy( lambda [ , IComparer < T > comparer] )
//在IOrderedEnumerable<TSource>集合上執行升序排序
ThenByDescending( lambda [ , IComparer < T > comparer] )
//在IOrderedEnumerable<TSource>集合上執行降序排序
Reverse( lambda [ , IComparer < T > comparer] )
//倒轉序列
7.分組
按lambda表達式返回的項進行分組
//按lambda表達式指定的項進行分組,返回一個IEnumerable<IGrouping<TKey,T>>
{
new Book{ Title="寂靜的春天", Price=19.8, Type="社科"},
new Book{ Title="單向度的人", Price=19.8, Type="社科"},
new Book{ Title="歷史研究", Price=10.8,Type="歷史"},
new Book{ Title="卡拉馬佐夫兄弟", Price=10.8,Type="小說"},
};
//單條件分組
var query = list.GroupBy(book => book.Type);
StringBuilder bs = new StringBuilder();
foreach (var group in query)
{
bs.Append("-----" + group.Key + "-----\r\n"); //Key是組頭,此處是book.Type
foreach (var book in group)
{
bs.Append(" " + book.Title + "\r\n");
}
Console.WriteLine(bs.ToString());
bs.Clear();
}

//多條件分組,同時滿足指定的條件會被分為一組
var query = list.GroupBy(book =>new { book.Type, book.Price });
StringBuilder bs = new StringBuilder();
foreach (var group in query)
{
bs.Append("-----" + group.Key.Type + "-----\r\n"); //Key是匿名對象,此處是new { book.Type, book.Price }
foreach (var book in group)
{
bs.Append(" " + book.Title + "\r\n");
}
Console.WriteLine(bs.ToString());
bs.Clear();
}

ToLookup(lambda )
//與GroupBy是一樣的,但不延遲查詢,返回一個ILookup<TKey, T>,該類型是IEnumerable<IGrouping<TKey, T>> 的簡化版
var grouping = list.ToLookup(book => book.Type); //立即分組
foreach (var group in grouping)
{
Console.WriteLine($"========{group.Key}========");
foreach(var item in group)
{
Console.WriteLine(item.Title);
}
}
8.聯結
將N張表(集合)建立聯結,每張表都有一個共同的鍵,鍵相同的行數據則被歸納到一行中, 下表中的出版社和圖書以出版社ID為關聯鍵位,使用聯結查詢后,相同關聯鍵位的行數據會被整合到一行中
9-1.內聯結:查詢關聯的多張表,但不返回無關聯的記錄(inner join)
Join ( 聯結的另一個集合,能返回被查詢的左邊集合的關聯鍵位的函數,能返回被聯結的右邊集合的關聯鍵位的函數,根據前兩個函數的參數能創建新結果集的函數 )

//適用於1對1、1對多關系,類似於sql的inner join,無關聯的記錄不會返回
var query = publishers.Join(books, publish => publish.ID, book => book.PublisherID, (publish, book) => new
{
pubID = publish.ID,
pubName = publish.Name,
bookName = book.Name
});

9-1.分組聯結:將關聯的多張表的記錄進行分組
單表分組使用GroupBy,多表連接分組則使用GroupJoin
GroupJoin ( 聯結的另一個集合,能返回被查詢的左邊集合的關聯鍵位的函數,能返回被聯結的右邊集合的關聯鍵位的函數,根據前兩個函數的參數能創建新結果集的函數 )

{
pubID = publish.ID,
pubName = publish.Name,
bookAllName = !bookList.Any()==true?"無":string.Join(",",bookList.Select(b=>b.Name))
});

9-2.外連接:鍵位不相等時,保證左邊可以返回,右邊則以null填充(left join)
使用GroupJoin 方法,利用投影和DefaultIfEmpty方法可實現左外連接。

var query = publishers.GroupJoin(books, p => p.ID, b => b.PublisherID, (publish, bookList) => new { publish.ID, publish.Name, bookList }).
SelectMany(x => x.bookList.DefaultIfEmpty(), (publish, book) => new
{
pubID = publish.ID,
pubName = publish.Name,
bookName = book == null ? "無" : book.Name
});

左聯結的表達式版本
join p in publishers
on b.PublisherID equals p.ID
into newTable
from x in newTable.DefaultIfEmpty( )
select new
{
ID = b.ID,
Name = b.Name,
pubName = x==null? "null":x.Name
};
大部分情況下可能會使用GroupJoin方法,但是假如關鍵鍵位本身是必填的,那么使用Join方法就可以了,因為關聯鍵位是必填,則不會存在關聯到空數據的情況,也就沒必要使用GroupJoin。
10.全連接
在sql中存在全連接的概念,它是指兩張或N張表無論左或右出現了未匹配上的行時,都以null填充。在linq中並不支持全連接,如果有這種需求,可以考慮先得到兩個結果集,最后再UNION即可。
11.交叉連接
也稱笛卡爾積查詢,可使用linq表達式寫個簡單的例子:
{
'A' , 'B' , 'C'
};
List < char > bList = new List < char >
{
'x' , 'y'
};
var query =
from a in aList
from b in bList
select new { a , b };
foreach ( var item in query )
{
Console . WriteLine ( $" { item . a } 與上 { item . b } " );
}
12.串聯
將5另一個序列與當前序列合並為一個序列
13.分區
Skip():跳過集合中指定個數的項,返回剩下的項。
SkipWhile():返回滿足條件的項。
Take():從索引起始位置開始提取指定個數的項。
TakeWhile():提取滿足條件的項
14.生成
DefaultIfEmpty() :用於當集合為空時為集合提供帶有默認值的一個項
15.判斷
All() :集合中所有項都滿足條件嗎?
Any():集合至少包含了一個項嗎?
Contains():集合包含了參數指定的項嗎?
16.比較
LINQ To Object
查詢泛型集合
所有的LINQ操作符(即擴展方法)均定義在System.Linq.Enumerable靜態類中,為所有實現了IEnumerable<T>的強類型集合擴展出了LINQ查詢方法。所以數組、泛型集合都可以使用LINQ查詢。

var records = objArray.Select(m => m.GetType().FullName).OrderBy(t => t);
ObjectDumper.Write(records);
Book[] books =
{
new Book{ Title="萬有引力之虹", Isbn="993748928", PageCount=300 },
new Book{ Title="解體概要", Isbn="325757665", PageCount=500 },
new Book{ Title="寂靜的春天", Isbn="229911000", PageCount=200 }
};
var records = books.Where(b => b.Isbn.Contains("9")).Select(b => b.Title);
ObjectDumper.Write(records);
List<Book> bList = new List<Book>
{
new Book{ Title="萬有引力之虹", Isbn="993748928", PageCount=300 },
new Book{ Title="解體概要", Isbn="325757665", PageCount=500 },
new Book{ Title="寂靜的春天", Isbn="229911000", PageCount=200 }
};
var records = bList.Where(b => b.Isbn.Contains("9")).Select(b => b.Title);
ObjectDumper.Write(records);
Dictionary<string, int> bNary = new Dictionary<string, int>
{
{ "sam", 12 },
{ "corz", 22 },
{ "korn", 53 },
};
var records = bNary.Where(o => o.Value > 20);
ObjectDumper.Write(records);
查詢非泛型集合
只需要使用Cast<T>將非泛型集合轉換為泛型即可。

ArrayList list = new ArrayList()
{
new Book{ Title="寂靜的春天"},
new Book{ Title="萬有引力之虹"},
new Book{ Title="解體概要"}
};
var records = list.Cast<Book>().Select(b => new { bName= b.Title });
參數化查詢
可在查詢中使用變量,還可以動態構造查詢,比如定義一個函數,函數以Func泛型委托做參數,通過條件測試傳遞不同的Lambda表達式。

<select name="combobox">
<option value="0">查詢標題</option>
<option value="1">查詢出版社</option>
</select>
<div>
@ViewData["show"]
</div>
</body>

public ActionResult Index(string combobox)
{
string recordsJson = string.Empty;
switch (combobox)
{
case "0":
recordsJson=ComboboxLambda(b => b.Title);
break;
case "1":
recordsJson=ComboboxLambda(b=>b.Publisher.Name);
break;
}
ViewData["show"] = recordsJson;
return View();
}
[NonAction]
public string ComboboxLambda<T>(Func<Book,T> selector)
{
var records = SampleData.books.Select(selector);
return JsonConvert.SerializeObject(records);
}
LINQ查詢是一系列的鏈式操作,所以完全可以根據條件動態增加查詢,所以以下代碼並不會發生覆蓋而是追加。

public ActionResult Index(int maxPage, string orderByTitle)
{
IEnumerable<Book> books = SampleData.books;
if (maxPage != 0)
{
books = books.Where(b => b.PageCount > maxPage);
}
if (!string.IsNullOrEmpty(orderByTitle))
{
books = books.OrderBy(b => b.Title);
}
books = books.Select(b => b); //查詢會在符合條件的判斷中形成鏈式操作
ViewData["show"] = JsonConvert.SerializeObject(books);
return View();
}
讀取文件
一個txt文件存儲了圖書信息,為StreamReder添加一個擴展方法用於獲取所有行,再通過LINQ查詢將數據打包。

{
/// <summary>
/// 讀取每一行
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static IEnumerable<string> Lines(this StreamReader source)
{
string line;
while (!string.IsNullOrEmpty(line = source.ReadLine()))
{
yield return line;
}
}
}

{
string filePath = Server.MapPath("~/bookMessage.txt");
StreamReader reader = new StreamReader(filePath);
using (reader)
{
var bookMsg = reader.Lines()
.Where(line => !line.StartsWith("#")) //過濾掉首行
.Select(line => line.Split(','))
.Select(part => new
{
Isnb = part[0],
title = part[1],
publisher = part[2],
author = part[3].Split(';').Select(authorPerson => authorPerson)
});
ViewData["show"] = JsonConvert.SerializeObject(bookMsg);
}
return View();
}
LINQ To XML
XObject類

//添加注釋節點。
Annotation(Type)
//獲取第一個注釋節點,類似行為的有Annotation<T>()、Annotations(Type)、Annotations<T>()。
XNode類
表示項、注釋、 文檔類型、處理指令、文本節點。節點可以是項節點、屬性節點、文本節點。

//緊跟在此節點之后添加指定的內容
AddBeforeSelf(object)
//緊跟在此節點之前添加指定的內容
Remove()
//從父節點總移除自身
Ancestors()
//獲取當前節點的祖先元素節點集合
ElementsAfterSelf()
//獲取當前節點后面的兄弟元素節點集合
ElementsBeforeSelf()
//獲取當前節點的前面的兄弟元素節點集合
NodesAfterSelf()
//獲取當前節點后面的兄弟元素節點集合
NodesBeforeSelf()
//獲取當前節點前面的兄弟元素節點集合
XContainer類

//獲取當前節點包含的所有子節點集合
Elements()
//獲取當前節點包含的所有子元素節點集合
Elements(XName)
//獲取當前節點包含的所有能匹配參數指定的XName的子元素節點集合
Element(XName)
//獲取當前節點包含的能匹配參數指定的XName的第一個子元素節點
Descendants()
//獲取當前節點包含的所有子代元素節點集合,即后代元素節點集合
DescendantNodes()
//獲取當前節點包含的所有子代節點集合,即后代節點集合
Descendants(XName)
//獲取當前節點包含的所有能匹配參數指定的XName的子代元素節點集合,即后代元素節點集合
Add(object)
//添加子節
AddFirst(object)
//將參數指定的節點添加為作為自身包含的第一個子節
RemoveNodes()
//刪除自身的所有子節
ReplaceNodes(object)
//將自身包含的所有子節替換為參數指定的節點
ReplaceWith(object)
//將自身替換為參數指定的節點
XElement類
表示XML項節點。

//XElement的構造函數,用於創建XML元素節點,參數2如果是String則成為元素節點包含的文本節點,否則可同時創建出后代元素節點
XNameString:元素節點名稱的字符表示或XName對象
//示例1:使用函數式鏈式操作創建XML元素節點
XElement books = new XElement("books",
new XElement("book",
new XElement("author", "寒食"),
new XElement("author", "寒食")
)
);
//示例2:調用函數創建XML元素節點
XElement book = new XElement("book");
book.Add(new XElement("author","寒食"));
book.Add(new XElement("author", "無垠"));
XElement books = new XElement("books");
books.Add(book);
//示例3:創建命名空間
XElement books = new XElement("{http://google.com/}books",
new XElement("book",
new XElement("author", "寒食"),
new XElement("author", "寒食")
)
);
//示例4:創建命名空間前綴
XElement books = new XElement("books",
new XElement("book",
new XAttribute(XNamespace.Xmlns + "1", ns),
new XElement("author", "寒食"),
new XElement("author", "寒食")
)
);
Add(XElement)
//添加子元素節點
Save()
//保存XML文檔
WriteTo(XmlWriter)
//將元素節點寫入XmlWriter中
Attribute(XName)
//獲取屬性節點集合
Attribute(XName)
//根據指定的屬性節點名獲取屬性節點值
AncestorsAndSelf()
//獲取自身並包括其祖先元素節點集合
DescendantsAndSelf()
//獲取自身並包括其后代元素節點集合
RemoveAll()
//移除所有后代
RemoveAttributes()
//移除自身的所有屬性節點
RemoveAnnotations(Type)
//移除自身的所有注釋節點
SetAttributeValue(XName, Object)
//根據指定的屬性節點名設置屬性節點值
SetElementValue(XName, Object)
//根據指定的屬性節點名設置子元素節點的屬性節點值
//==========靜態方法==========
load(Path, LoadOptions)
//加載XML文檔
//LoadOptions:可選的枚舉,可能的值有:
//None:不保留無意義的空白
//PreserveWhitespace:保留無意義的空白
//SetBaseUri:保留URI信息
//SetLineInfo:保留請求的行信息
//示例:
try
{
XElement x = XElement.Load(Server.MapPath("/books.xml"), LoadOptions.PreserveWhitespace); // 可從URL、磁盤路徑加載
}
Parse()
//從XML字符串解析出XElement
//示例:
XElement x = XElement.Parse(@"
<book>
<title>LINQ in Action</title>
<author>Fabrice Marguerie</author>
<author>Steve Eichert</author>
<author>Jim Wooley</author>
<publisher>Manning</publisher>
<rating>4</rating>
</book>
");
XDocument類
表示XML文檔,與XElement一樣,它們都提供Load()、Parse()、Save()和WriteTo()方法,但此類可以包含更多信息,如包含一個根項的XElement、XML聲明、XML文檔類型和XML處理指令。如果使用函數式鏈式操作創建XML項,則使用XDocument與使用XElement創建XML項的語法格式是完全一樣的。

XDocument doc = new XDocument("books",
new XDeclaration("1.0", "utf-8", "yes"), // 表示XML文檔版本、字符編碼、是否是獨立信息的節點
new XProcessingInstruction("XML-sylesheet", "friendly-rss.xsl"), // 表示XML文檔處理指令的節點,此處為XML文檔配置了一個樣式表用以格式化XML文檔以便在瀏覽器以友好的界面顯示XML數據
new XDocumentType("HTML", "-//w3c//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict/dtd", null) // 表示XML文檔類型聲明的節點
)
);
XAttribute類

//從父元素節點中移除自身
//==========屬性==========
Parent
//獲取父元素節點
XName
表示項的名字或項屬性的名字
讀取XML的簡單示例

<category name="知識">
<childcategory name="自然">
<books>
<book>寂靜的春天</book>
<book>自然之力</book>
</books>
</childcategory>
<childcategory name="宗教">
<books>
<book>佛陀的證悟</book>
</books>
</childcategory>
<childcategory name="社會">
<books>
<book>智利天下寫春秋</book>
<book>文明的解析</book>
</books>
</childcategory>
</category>

{
public ActionResult Index()
{
XElement root = XElement.Load(Server.MapPath("~/books.xml"), LoadOptions.PreserveWhitespace);
var childcategory = root.Element("childcategory"); // 獲取第一個childcategory元素節點
var childcategoryAttri = childcategory.Attribute("name"); // 獲取第一個childcategory的name屬性節點
IEnumerable<XElement> books = childcategory.Element("books").Elements("book"); // 獲取第一個childcategory所包含的第一個books元素節點包含的所有book元素節點
ViewData["childcategory"] = childcategory;
ViewData["childcategoryAttri"] = childcategoryAttri;
ViewData["childs"] = string.Join("", books.ToList());
// 輸出XElement時會將它所包含的所有后代一並輸出
// 輸出 IEnumerable<XElement>元素節點集合時必須ToList后與字符相連
return View();
}
}

// (string)XElement可將元素節點轉為其包含的文本 這樣就可以執行一次判斷 前提是該元素節點和包含的文本是在一行顯示的
ViewData["show"] =string.Join("",root.Descendants("book").Where(book => (string)book == "寂靜的春天"));
LINQ To Entity
//如果Where后沒有ToList,而是直接調用Select方法將會引發異常
var list = dbcontext.UserManagers.Where(user => user.LoginName == "a").ToList().Select((p, i) => new { u = p.LoginName, id = p.UserId, index = i }).ToList();
DbSet<TEntity> 類
//使用預加載策略建立左聯結查詢,模型必須具有導航屬性,此方法根據導航屬性來查詢與主實體所關聯的其它實體,此方法會立即開啟查詢
MusicStoreDB db = new MusicStoreDB();
var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre); //Artist和Genre都是Album的導航屬性,不需要像Join方法那般指定主外鍵,只需要指定導航屬性即可建立左聯結查詢
//批量刪除記錄
//示例:
public ContentResult DelBtch(string IDs) //IDs,需要被刪除的記錄的ID,如"1,15,32"
{
try
{
var records = DBContext.TbRights.RemoveRange(DBContext.TbRights.Where(t => IDs.Contains(t.TbRightId.ToString())));
DBContext.SaveChanges();
DBContext.Dispose();
return Content("{msg:'操作成功'}");
}
catch
{
return Content("{msg:'操作失敗'}");
}
}
AddRange()
//批量添加記錄
AddOrUpdate(TEntity[] )
//System.Data.Entity.Migrations命名空間中為DbSet<TEntity>定義的擴展,自動識別插入或更新,當實體主鍵在數據庫表中不存在時視為插入,當實體主鍵在數據庫表中存在時視為更新。在參數數組包含的實體的主鍵在數據庫表中既有存在的也有不存在的情況時,沒關系,該更新該插入,此方法自動幫你完成。
//注意:如果某個字段為空,也將插入或更新到數據庫,如果數據庫設置了不允許空則引發異常
//示例:
var dirtyRecs = JsonConvert.DeserializeObject<List<TbRight>>(dirtyRecords); //包含了需要更新和需要插入的實體
DBContext.TbRights.AddOrUpdate(dirtyRecs.ToArray() ); //同時執行了插入和更新
插入數據前檢測數據庫是否已經具有一條完全相同的記錄

/*
xTbUserRight:需要插入數據庫的記錄的Json表示
userIDs:以逗號分隔的員工ID的字符表示
checkValues:以逗號分隔的權限ID的字符表示
查詢員工權限表時先對照userIDs和checkValues查出相同的記錄,如果存在這樣的記錄則先刪除它們
最后將xTbUserRight轉化為的實體記錄集合插入數據庫
*/
public ContentResult AddTbUserRightBtch( string xTbUserRight , string xUserIDs , string xCheckValues )
{
int [ ] userIDs = Array.ConvertAll ( xUserIDs.Split ( ',' ) , o => int.Parse ( o ) );
int [ ] checkValues = Array.ConvertAll ( xCheckValues.Split ( ',' ) , o => int.Parse ( o ) );
var newRecords = JsonConvert.DeserializeObject<List<TbUserRight>> ( xTbUserRight );
var oldRecords = DBContext.TbUserRights.Where ( t => userIDs.Contains ( t.UserId ) && checkValues.Contains ( t.TbRightId ) );
if ( oldRecords.Count ( ) != 0 )
{
DBContext.TbUserRights.RemoveRange ( oldRecords );
}
DBContext.TbUserRights.AddRange ( newRecords );
DBContext.SaveChanges ( );
return Content ( "{msg:'操作成功'}" );
}
#endregion
根據某個字段的數據集合查詢出另一張表中對應的記錄

//UserAuthority是用戶權限表實體,它存儲三個字段,主鍵、用戶ID和用戶權限ID,一個用戶具有多個權限ID,結構如下:
//PrimaryID UserID AuthorityID
// 1 32 20
// 2 32 26
//Authority是權限表實體,它存儲兩個字段,主鍵和權限名稱,結構如下:
//AuthorityID AuthorityName
// 32 ERP登錄權限
//現在要查詢出當前用戶所具有的所有權限的記錄
var userAuthorityID = DBContext.UserAuthority.Where ( t => t.UserID == UserId ).Select ( t => t.AuthorityID ).ToList ( ); //獲取用戶權限ID集合
var userInclud = DBContext.Authority.Where ( t => userAuthorityID.Contains ( t.AuthorityID ) ); //獲取用戶具有的權限記錄
var userNotInclud = DBContext.Authority.Where ( t => !userAuthorityID.Contains ( t.AuthorityID ) ); //獲取用戶不具有的權限記錄