Cast的妙用:泛用LINQ 語句

泛用LINQ語句的概念很簡單,在一些情況下,我們會有需求使用同一段程式碼來對不同資料表做查詢,這在ADO.NET中很容易達到,見下例

 

Cast的妙用:泛用LINQ 語句
 
/黃忠成
 
什麼是泛用LINQ 語句
 
   泛用LINQ語句的概念很簡單,在一些情況下,我們會有需求使用同一段程式碼來對不同資料表做查詢,這在ADO.NET中很容易達到,見下例:

 

static void PrintCustomerID(SqlDataReader reader)
{
    Console.WriteLine(reader.GetString(reader.GetOrdinal("CustomerID")));
}
此函式接受一個Reader物件,然後頃印CustomerID欄位值,這不受限於SqlDataReader所選取的Schema或是資料表,只要Schema中有CustomerID欄位即可。
不過,這樣的手法在LINQ這種Typed-Query(具型別查詢語句)模式下,並沒有很直覺的寫法,因為你不能寫下下面的句子。

 

static void Test2(int index)
{
      var query;
      DataClasses1DataContext context = new DataClasses1DataContext();
      context.Log = Console.Out; //for log only,you can remove it.
      if (index == 1)
          query = context.Customers;
      else
          query = context.Orders;
 
      var result = from s1 in query where s1.CustomerID.Contains("V")
                   select s1;
      foreach (var item in result)
      {
         Console.WriteLine(item.CustomerID);
      }
}
編譯器會抱怨,var的變數必須在宣告時指定。
那要如何在LINQ To SQL或是LINQ To Entites達到同樣的效果呢?這有幾個方法可以做到。

 

1、使用ExecuteQuery,並使用另一個Typed物件來接收回傳集。
2、使用實體類別(Entity Class)繼承。
3、使用Castpartial class
12對熟悉LINQ To SQL的讀者應該不難,所以我就不再贅述了,第三個手法是較少見的,我們可以運用partial class機制,讓Entity Classes實作特定介面,然後以Cast函式來達到目的。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.SqlClient;
 
namespace ConsoleApplication39
{
    class Program
    {
        static void Main(string[] args)
        {
            Test(1);
            Console.WriteLine("------");
            Test(0);
            Console.ReadLine();
        }
 
        static void Test(int index)
        {
            IQueryable<IGenericBaseClass> query = null;
            DataClasses1DataContext context = new DataClasses1DataContext();
            context.Log = Console.Out; //for log only,you can remove it.
            if(index == 1)
                query = context.Customers.Cast<IGenericBaseClass>();
            else
                query = context.Orders.Cast<IGenericBaseClass>();
 
            var result = from s1 in query where s1.CustomerID.Contains("V") select s1;
            foreach (var item in result)
            {
                Console.WriteLine(item.CustomerID);
            }
        }
    }
 
    public interface IGenericBaseClass
    {
        string CustomerID { get; set; }
    }
 
    partial class Customers : IGenericBaseClass
    {
    }
 
    partial class Orders : IGenericBaseClass
    {
    }
}
仔細揣摩上面的程式碼,我相信你會找到一個不一樣的LINQ應用手法。