Note introducting LINQ

 LINQ is a methodology that simplifies and unifies the implenentation of any kind of data access.  It offering a uniform way to access and manage data without forcing the adoption
of a "one size fies all" model.  It is a programming model that introduces queries as a
first-class concept into any Microsoft.Net language.However, complete support for LINQ
requires some extensions int the language used.  These extensions boost productivity, thereby
providing a shorter, meaningful, and expressive syntax to manipulate data.

A simple LINQ query for a typical software solution that returns the names of customers in Italy:

 

var query = 
    from   c 
in Customers
    
where  c.Country == "Italy"
    select c.CompanyName;

foreach(string name in query) {
    Console.WriteLine( name );
}

 

The result of this query is a list of stirngs.  You can enumerate these values with a
foreach loop in C#.

*The same query(and the following foreach code) can be applied to an SQL database,to a DataSet, to an array of object in memory,or to many other kinds of data. Customers could
be a collection of objects.

Like this:

 

Customer[] Customers;

DataDet ds 
= GetDataSet();

DataTable Customers 
= ds.Tables["Customers"];

Customers could be an entity class that describies a physical table in a relational database.

DataContext db = new DataContext(ConnectionString);
Table<Customer> Customers = db.GetTable<Customer>();

describies a conceptual model and is mapped to a relational database.

NorthwindModel dataModel = new NorehwindModel();
ObjectQuery<Customer> Customers = dataModel.Customers;


Customer[]Customers=GetCustomers();
varquery=
fromcinCustomers
wherec.Country=="Italy"
selectc;

the compiler generates this code:

Customer[]Customers=GetCustomers();
IEnumerable<Customer>query=
Customers
.Where(c=>c.Country=="Italy");

becomes longer, as you see here:
varquery=
fromcinCustomers
wherec.Country=="Italy"
orderbyc.Name
selectnew{c.Name,c.City};
the generated code is longer too:
var query=
Customers
.Where(c=>c.Country=="Italy");
.OrderBy(c=>c.Name)
.Select(c=>new{c.Name,c.City});

The code apparently calls instance members on the object returaned from the previous

The Var keyword used to declare query infers the variable type declaration from the initial
assignment,which in this case will return an IEnumerable<T> type.

*The important concept is the timing of operations over data.In general,a LINQ query is
not really executed until there is access to the query result,because it describies a set
of operations that will be performed when necessary.
The access to a query result does the real work.

This can be illustrated in the case of a foreach loop:
varquery=fromcinCustomers...
foreach (stringnameinquery)...
There are also methods that iterate a LINQ query result, producing a persistent copy of data
in memory. For example, the ToList method produces a typed List<T> collection:
varquery=fromcinCustomers...
List<Customer>customers= query.ToList();
When the LINQ query operates on data that is on a relational database (such as Microsoft
SQL Server), the LINQ query generates an equivalent SQL statement instead of operating
with in-memory copies of data tables. The query execution on the database is delayed until
the first access to the query result. Therefore, if in the last two examples Customers was a
Table<Customer> type (a physical table in a relational database) or an ObjectQuery<Customer>
type (a conceptual entity mapped to a relational database), the equivalent SQL query would
not be sent to the database until the foreach loop was executed or the ToList method was
called. The LINQ query can be manipulated and composed in different ways until that time.


At first sight, LINQ might appear to be just another SQL dialect. This similarity has its roots in
the way a LINQ query can describe a relationship between entities such as an SQL join:
varquery=
fromcinCustomers
joinoinOrders
onc.CustomerIDequalso.CustomerID
selectnew{c.CustomerID,c.CompanyName,o.OrderID};

var query =
              from   c in Customers
              join   s in Suppliers
                     on c.City equals s.City
              select new { c.City, c.Name, SupplierName = s.Name };

         And something like the following will be returned:

          City=Torino     Name=Marco       SupplierName=Trucker
          City=Dallas     Name=James       SupplierName=FastDelivery
          City=Dallas     Name=James       SupplierName=Horizon
          City=Seattle    Name=Frank       SupplierName=WayFaster

When you build a LINQ query,it is always a set of Operations on instances of some classes.

    Note    You can create entity classes by using code-generation tools such as SQLMetal or
             the LINQ to SQL Designer in Microsoft Visual Studio.

          In Listing 1-3, you can see an example of a Product class that maps a relational table named
          Products, with five columns that correspond to public data members.

          Listing 1-3  Class declaration mapped on a database table

             [Table("Products")]
             public class Product {
                 [Column(IsPrimaryKey=true)] public int IdProduct;
                 [Column(Name="UnitPrice")] public decimal Price;
                 [Column()] public string ProductName;
                 [Column()] public bool Taxable;
                 [Column()] public decimal Tax;
             }
When you work on entities that describe external data (such as database tables), you can
          create instances of these kinds of classes and manipulate in-memory objects just as if data
          from all tables were loaded in memory. These changes are submitted to the database through
          SQL commands when you call the SubmitChanges method, as you can see in Listing 1-4.

          Listing 1-4  Database update calling the SubmitChanges method

          

   var taxableProducts = 
                 from   p 
in db.Products 
                 
where  p.Taxable == true 
                 select p; 
             
foreach( Product product in taxableProducts ) 
                 RecalculateTaxes( product ); 
             }
 
             db.SubmitChanges(); 

          The Product class in the preceding example represents a row in the Products table of an
          external database. When SubmitChanges is called, all changed objects generate an SQL
          command to update the corresponding rows in the table.

LINQ has a different set of classes and extensions to support the manipulation of XML data.
Imagine that your customers are
          able to send orders using XML files like the ORDERS.XML file shown in Listing 1-5.

          Listing 1-5  A fragment of an XML file of orders

 

             <?xml version="1.0" encoding="utf-8" ?> 
             
<orders xmlns="http://schemas.devleap.com/Orders"> 
                 
<order idCustomer="ALFKI" idProduct="1" quantity="10" price="20.59"/> 
                 
<order idCustomer="ANATR" idProduct="5" quantity="20" price="12.99"/> 
                 
<order idCustomer="KOENE" idProduct="7" quantity="15" price="35.50"/> 
             
</orders> 


*Using standard Microsoft .NET 2.0 System.Xml classes,you can load the file using a DOM
approach or you can parse its contents using an XmlReader implementation.
If you need to extract all the products ordered with their quantities, you can parse the orders
          file using an XmlReader to accomplish this, as shown in Listing 1-6.

          Listing 1-6  Reading the XML file of orders using anXmlReader

             String nsUri = "http://schemas.devleap.com/Orders";
             XmlReader xmlOrders = XmlReader.Create( "Orders.xml" );

    

         List<Order> orders = new List<Order>(); 
             Order order 
= null
             
while (xmlOrders.Read()) 
                 
switch (xmlOrders.NodeType) 
                     
case XmlNodeType.Element: 
                          
if ((xmlOrders.Name == "order"&& 
                          (xmlOrders.NamespaceURI 
== nsUri)) 
                              order 
= new Order(); 
                              order.CustomerID 
= xmlOrders.GetAttribute( "idCustomer" ); 
                              order.Product 
= new Product(); 
                              order.Product.IdProduct 
= 
                                  Int32.Parse( xmlOrders.GetAttribute( 
"idProduct" ) ); 
                              order.Product.Price 
= 
                                  Decimal.Parse( xmlOrders.GetAttribute( 
"price" ) ); 
Introducing Microsoft LINQ 

                             order.Quantity 
= 
                                  Int32.Parse( xmlOrders.GetAttribute( 
"quantity" ) ); 
                             orders.Add( order ); 
                         }
 
                         
break
                 }
 
             }
 

          You could also use an XQuery like the following one to select nodes:

          for $order in document("Orders.xml")/orders/order
          return $order

shows a LINQ to XML query made over the orders file.

          Listing 1-7  Reading the XML file using LINQ to XML

 

             XDocument xmlOrders = XDocument.Load( "Orders.xml" ); 

             XNamespace ns 
= "http://schemas.devleap.com/Orders"
             var orders 
= from o in xmlOrders.Root.Elements( ns + "order" ) 
                          select 
new Order { 
                                      CustomerID 
= (String)o.Attribute( "idCustomer" ), 
                                      Product 
= new Product { 
                                          IdProduct 
= (Int32)o.Attribute("idProduct"), 
                                          Price 
= (Decimal)o.Attribute("price") }, 
                                      Quantity 
= (Int32)o.Attribute("quantity"
                                  }; 

 

In SQL, you can write the following:

          SELECT * FROM Customers WHERE Country = 'Italy'

          In C#, you would probably write this:

          public List<Customer> ItalianCustomers( Customer customers[] )
           {
              List<Customer> result = new List<Customer>();
              foreach( Customer c in customers ) {
                  if (c.Country == "Italy") result.Add( c );
              }
              return result;
          }

IEnumerable<T> interface. You can use LINQ to write a query over Reflection:

var query =
    from     assembly in AppDomain.CurrentDomain.GetAssemblies()
    from     type in assembly.GetTypes()
    from     method in type.GetMethods()
    where    method.IsStatic
             && method.ReturnType.GetInterface( "IEnumerable`1" ) != null
    orderby method.DeclaringType.Name, method.Name
    group    method by new { Class = method.DeclaringType.Name,
                              Method = method.Name };

The equivalent C# code that handles data is longer to write, harder to read, and probably more
error prone. You can see a possible version that is not particularly optimized in Listing 1-10.

Listing 1-10  C# code equivalent to a LINQ query over Reflection

   

List<String> results = new List<string>(); 
   
foreach( var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
       
foreach( var type in assembly.GetTypes() ) 
            
foreach( var method in type.GetMethods()) 
                
if (method.IsStatic && 
                    method.ReturnType.GetInterface(
"IEnumerable`1"!= null
                    
string fullName = String.Format( "{0}.{1}"
                                           method.DeclaringType.Name, 
                                           method.Name ); 
                    
if (results.IndexOf( fullName ) < 0
                        results.Add( fullName ); 
                    }
 
                }
 
            }
 
       }
 
   }
 

   results.Sort();
Many possible evolutions could originate form LINQ, and we should not forget that SQL is a
widely adepted standard that cannot be easily replaced by another.

extension  [ex·ten·sion || ɪk'stenʃn]
n.  延长, 范围, 扩充
boost  [buːst]
n.  推进, 增加, 支援
v.  举, 抬; 推动; 推; 促进
thereby 
adv.  因此, 在那方面, 从而
expressive  [ex·pres·sive || ɪk'spresɪv]
adj.  表达的
syntax  [syn·tax || 'sɪntæks]
n.  语法; 有条理的排列; 句法
manipulate  [ma·nip·u·late || mə'nɪpjəleɪt /-jʊl-]
v.  操纵, 操作, 利用
typical  [typ·i·cal || 'tɪpɪkl]
adj.  典型的, 象征性的
entity  [en·ti·ty || 'entətɪ]
n.  实体; 本质; 存在
compiler  [com·pil·er || kəm'paɪlə]
n.  从高级语言原始码制造程序的程序 (计算机用语); 编辑者; 编译器
from now on 
从现在开始
domain  [do·main || dəʊ'meɪn]
n.  领土; 范围; 领地, 自治区; 因特网根据国家和组织类型的分类 (计算机用语)
instance  [in·stance || 'ɪnstəns]
n.  例证, 情况, 建议
v.  引以为例, 获得例证
declare  [de·clare || dɪ'kleə]
v.  断言; 宣布; 宣称; 声明, 表示
concept  [con·cept || 'kɒnsept]
n.  观念; 概念
preform  ['prɪː'fɔrm /-'fɔːm]
v.  预先形成
manipulation  [ma·nip·u·la·tion || mə'nɪpjəleɪʃn /-jʊl-]
n.  处理; 操纵; 操作
parse  [pɑrz/pɑː-]
v.  解析; 符合语法
n.  分列, 为使程序处理容易而把输入分成小部分 (计算机用语)
evolution  [ev·o·lu·tion || ‚iːvə'luːʃn]
n.  进化, 进展, 发展
adept  [ad·ept || 'ædept]
adj.  熟练的, 内行的; 拿手的
n.  内行, 老手, 擅长者; 专家

posted @ 2008-03-08 22:43  William Zhao  阅读(152)  评论(0编辑  收藏  举报