C#3.0新增功能09 LINQ 基礎05 使用 LINQ 進行數據轉換

  • 2019 年 10 月 4 日
  • 筆記

語言集成查詢 (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; }  }

以下示例演示了查詢:

 1 class DataTransformations   2 {   3     static void Main()   4     {   5         // 創建第一個數據源   6         List<Student> students = new List<Student>()   7         {   8             new Student { First="Svetlana",   9                 Last="Omelchenko",  10                 ID=111,  11                 Street="123 Main Street",  12                 City="Seattle",  13                 Scores= new List<int> { 97, 92, 81, 60 } },  14             new Student { First="Claire",  15                 Last="O』Donnell",  16                 ID=112,  17                 Street="124 Main Street",  18                 City="Redmond",  19                 Scores= new List<int> { 75, 84, 91, 39 } },  20             new Student { First="Sven",  21                 Last="Mortensen",  22                 ID=113,  23                 Street="125 Main Street",  24                 City="Lake City",  25                 Scores= new List<int> { 88, 94, 65, 91 } },  26         };  27  28         // 創建第二個數據源  29         List<Teacher> teachers = new List<Teacher>()  30         {  31             new Teacher { First="Ann", Last="Beebe", ID=945, City="Seattle" },  32             new Teacher { First="Alex", Last="Robinson", ID=956, City="Redmond" },  33             new Teacher { First="Michiyo", Last="Sato", ID=972, City="Tacoma" }  34         };  35  36         // 創建查詢  37         var peopleInSeattle = (from student in students  38                     where student.City == "Seattle"  39                     select student.Last)  40                     .Concat(from teacher in teachers  41                             where teacher.City == "Seattle"  42                             select teacher.Last);  43  44         Console.WriteLine("The following students and teachers live in Seattle:");  45         // 執行查詢  46         foreach (var person in peopleInSeattle)  47         {  48             Console.WriteLine(person);  49         }  50  51         Console.WriteLine("Press any key to exit.");  52         Console.ReadKey();  53     }  54 }  55 /* 輸出:  56     The following students and teachers live in Seattle:  57     Omelchenko  58     Beebe  59  */

有關詳細資訊,請參閱 join 子句select 子句

選擇每個源元素的子集

有兩種主要方法來選擇源序列中每個元素的子集:

  1. 若要僅選擇源元素的一個成員,請使用點操作。 在以下示例中,假設 Customer 對象包含多個公共屬性,包括名為 City 的字元串。 在執行時,此查詢將生成字元串的輸出序列。
var query = from cust in Customers              select cust.City;
  1. 若要創建包含多個源元素屬性的元素,可以使用帶有命名對象或匿名類型的對象初始值設定項。 以下示例演示如何使用匿名類型封裝每個 Customer 元素的兩個屬性:
var query = from cust in Customer              select new {Name = cust.Name, City = cust.City};

有關詳細資訊,請參閱對象和集合初始值設定項匿名類型

將記憶體中對象轉換為 XML

LINQ 查詢可以輕鬆地在記憶體中數據結構、SQL 資料庫、ADO.NET 數據集和 XML 流或文檔之間轉換數據。 以下示例將記憶體中數據結構中的對象轉換為 XML 元素。

 1 class XMLTransform   2 {   3     static void Main()   4     {   5         // 使用集合初始值設定項創建數據源   6         // 學生類是在上述定義的   7         List<Student> students = new List<Student>()   8         {   9             new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},  10             new Student {First="Claire", Last="O』Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},  11             new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},  12         };  13  14         // 創建查詢  15         var studentsToXML = new XElement("Root",  16             from student in students  17             let scores = string.Join(",", student.Scores)  18             select new XElement("student",  19                        new XElement("First", student.First),  20                        new XElement("Last", student.Last),  21                        new XElement("Scores", scores)  22                     ) // end "student"  23                 ); // end "Root"  24  25         // 執行查詢  26         Console.WriteLine(studentsToXML);  27  28         // Keep the console open in debug mode.  29         Console.WriteLine("Press any key to exit.");  30         Console.ReadKey();  31     }  32 }

此程式碼生成以下 XML 輸出:

<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>

有關詳細資訊,請參閱在 C# 中創建 XML 樹 (LINQ to XML)

對源元素執行操作

輸出序列可能不包含源序列中的任何元素或元素屬性。 輸出可能是使用源元素作為輸入參數而計算得出的值序列。 以下簡單查詢在執行時會輸出一串字元串,其值表示基於 double類型的元素的源序列的計算結果。

如果查詢將被轉換為另一個域,則不支援在查詢表達式中調用方法。 例如,不能在 LINQ to SQL 中調用普通的 C# 方法,因為 SQL Server 沒有用於它的上下文。 但是,可以將存儲過程映射到方法並調用這些方法。 有關詳細資訊,請參閱存儲過程

class FormatQuery  {      static void Main()      {          // 數據源          double[] radii = { 1, 2, 3 };            // 查詢表達式          IEnumerable<string> query =              from rad in radii              select $"Area = {rad * rad * Math.PI:F2}";            // 執行查詢          foreach (string s in query)              Console.WriteLine(s);            Console.WriteLine("Press any key to exit.");          Console.ReadKey();      }  }  /* 輸出:      Area = 3.14      Area = 12.57      Area = 28.27  */