使用 LINQ 進行數據轉換
語言集成查詢 (LINQ) 不僅可用於檢索數據,而是還是一個功能強大的數據轉換工具。通過使用 LINQ 查詢,您可以將源序列用作輸入,並采用多種方式修改它以創建新輸出序列。您可以通過排序和分組來修改序列本身,而不必修改元素本身。但是,LINQ 查詢最強大的功能可能在於它能夠創建新類型。這一功能在 select 子句中實現。例如,可以執行下列任務:
將多個輸入序列合並到具有新類型的單個輸出序列中。
創建其元素只包含源序列中的各個元素的一個或幾個屬性的輸出序列。
創建其元素包含對源數據執行的操作結果的輸出序列。
創建不同格式的輸出序列。例如,您可以將 SQL 行或文本文件的數據轉換為 XML。
這只是幾個示例。當然,可以采用多種方式將這些轉換組合在同一查詢中。另外,一個查詢的輸出序列可用作新查詢的輸入序列。
將多個輸入聯接到一個輸出序列
可以使用 LINQ 查詢來創建包含多個輸入序列的元素的輸出序列。下面的示例演示如何組合兩個內存中的數據結構,但組合來自 XML 或 SQL 或數據集源的數據時可應用相同的原則。假定下面兩種類類型:
class Student
{
public string First { get; set; }
public string Last {get; set;}
public int ID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public List<int> Scores;
}
class Teacher
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public string City { get; set; }
}
下面的示例演示該查詢:
linq code
class DataTransformations
{
static void Main()
{
// Create the first data source.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana",
Last="Omelchenko",
ID=111,
Street="123 Main Street",
City="Seattle",
Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire",
Last="O’Donnell",
ID=112,
Street="124 Main Street",
City="Redmond",
Scores= new List<int> {75, 84, 91, 39}},
new Student {First="Sven",
Last="Mortensen",
ID=113,
Street="125 Main Street",
City="Lake City",
Scores= new List<int> {88, 94, 65, 91}},
};
// Create the second data source.
List<Teacher> teachers = new List<Teacher>()
{
new Teacher {First="Ann", Last="Beebe", ID=945, City = "Seattle"},
new Teacher {First="Alex", Last="Robinson", ID=956, City = "Redmond"},
new Teacher {First="Michiyo", Last="Sato", ID=972, City = "Tacoma"}
};
// Create the query.
var peopleInSeattle = (from student in students
where student.City == "Seattle"
select student.Last)
.Concat(from teacher in teachers
where teacher.City == "Seattle"
select teacher.Last);
Console.WriteLine("The following students and teachers live in Seattle:");
// Execute the query.
foreach (var person in peopleInSeattle)
{
Console.WriteLine(person);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
The following students and teachers live in Seattle:
Omelchenko
Beebe
*/
選擇各個源元素的子集
選擇源序列中的各個元素的子集有兩種主要方法:
1、若要只選擇源元素的一個成員,請使用點運算。在下面的示例中,假定 Customer 對象包含幾個公共屬性,其中包括名為 City 的字符串。在執行此查詢時,此查詢將生成字符串輸出序列。
var query = from cust in Customers
select cust.City;
2、若要創建包含源元素的多個屬性的元素,可以使用具有命名對象或匿名類型的對象初始值設定項。下面的示例演示如何使用匿名類型來封裝各個 Customer 元素的兩個屬性:
var query = from cust in Customer
select new {Name = cust.Name, City = cust.City};
將內存中的對象轉換為 XML
通過 LINQ 查詢,可以輕松地在內存中的數據結構、SQL 數據庫、ADO.NET 數據集和 XML 流或文檔之間轉換數據。下面的示例將內存中的數據結構中的對象轉換為 XML 元素。
Code
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
};
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let x = String.Format("{0},{1},{2},{3}", student.Scores[0],
student.Scores[1], student.Scores[2], student.Scores[3])
select new XElement("student",
new XElement("First", student.First),
new XElement("Last", student.Last),
new XElement("Scores", x)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
此代碼生成下面的 XML 輸出:
Code
< Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,92,81,60</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>75,84,91,39</Scores>
</student>
<student>
<First>Sven</First>
<Last>Mortensen</Last>
<Scores>88,94,65,91</Scores>
</student>
</Root>
對源元素執行操作
輸出序列可能不包含源序列的任何元素或元素屬性。輸出可能是通過將源元素用作輸入參數計算出的值的序列。在執行下面這個簡單查詢時,此查詢會輸出一個字符串序列,該序列值表示根據 double 類型的元素的源序列進行的計算。
Code
class FormatQuery
{
static void Main()
{
// Data source.
double[] radii = { 1, 2, 3 };
// Query.
IEnumerable<string> query =
from rad in radii
select String.Format("Area = {0}", (rad * rad) * 3.14);
// Query execution.
foreach (string s in query)
Console.WriteLine(s);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Area = 3.14
Area = 12.56
Area = 28.26
*/