LINQ学习笔记

Posted on 2007-12-03 00:40  TonyChen  阅读(919)  评论(0编辑  收藏  举报
Technorati 标签: LINQ C#3.0

1.   LINQ是什么?LINQ要解决什么问题?

a)         LINQ(Language-INtegrated Query) Orcas(VS2008) 提供的一套超强扩展功能,可以用一种标准、简单的方式查询和更新数据。被查询的数据可以是 .NET Framework collections SQL databasesADO.NET DatasetsXML documents,以及其他任何实现 IEnumerable<T> 的数据类型。LINQ 是一种语言扩展,可以使用类似 SQL 的近自然语法或扩展方法 API 来操作这些数据源。

b)        解决的问题

                        i.              Data != Object

                      ii.              统一集合数据查询模型

2.   C# 3.0的新特性,优雅

a)         隐式类型变量(Implicitly typed local variables)

var关键字,编译器翻译,不能在运行期改变类型

var a = 123;

var b = "123";

 

b)        扩展方法(Extension Method)

为既有类型添加额外的功能

(1) 必须在静态类中定义。

(2) 必须是静态方法。

(3) 第一个参数必须添加 this 关键字,且参数类型必须是目标类型。

(4) 扩展方法不能访问目标类型 privateprotected 成员。

(5) 同一目标类型不能有多个名称、签名一样的扩展方法。

(6) 如果扩展方法和目标类型方法名称和参数签名相同,则优先调用目标类型方法。

static class StringExtension

{

    public static void PrintLine(this string s)

    {

        Console.WriteLine(s);

    }

 

    public static void PrintLine(this string s, int count)

    {

        for (int i = 0; i < count; i++)

        {

            Console.WriteLine(s);

        }

    }

}

 

c)         对象初始化(Object initializers

class MyClass

{

    public MyClass()

    {

    }

 

    public MyClass(int x, int y)

    {

        this.x = x;

        this.y = y;

    }

 

    private int x;

 

    public int X

    {

        get { return x; }

        set { x = value; }

    }

 

    private int y;

 

    public int Y

    {

        get { return y; }

        set { y = value; }

    }

 

    private string s;

 

    public string S

    {

        get { return s; }

        set { s = value; }

    }

}

 

Call Code:

MyClass o1 = new MyClass { X = 1, Y = 2, S = "abc" };

MyClass o2 = new MyClass { X = 1, Y = 2 };

MyClass o3 = new MyClass(1, 2) { S = "abc" };

 

d)        匿名属性(Automatic properties)

(1) 必须同时包含 get; set; 定义。(由于关联字段是编译器自动生成的,没有 set 访问器也就意味着永远没有办法为该属性赋值。同理,没有 get 也不成。)

(2) 可以为 get; set; 定义不同的访问权限。

class MyClass

{

    public int X { get; set; }

public int Y { get; set; }

public int Z { get; internal set; }

public string S { get; set; }

}

 

e)         匿名类型(Anonymous types)

var o1 = new { X = 1, Y = 2, S = "abc"};

var o2 = new { X = 1, Y = 2, S = "abc"};

Console.WriteLine(o1 == o2);

Console.WriteLine(o1.GetType() == o2.GetType());

匿名类型特征:

(1) 编码时没有定义类型名称。

(2) 通过对象初始化器定义属性。

(3) 引用变量只能是隐式类型或 Object

      

应用环境:

(1) 局部信息存储交换。

(2) LINQ 返回信息存储。

(3) 用于数据控件绑定源。

      

f)         Lambda expressions

.Net 1.1时代的委托

public delegate bool NumberTester(int i);

 

public static bool IsOdd(int i)

{

    return (i % 2) == 1;

}

 

public static void PrintMatchingNumbers(int from, int to, NumberTester filter)

{

    for (int i = from; i <= to; ++i)

    {

        if (filter(i))

        {

            Console.WriteLine(i);

        }

    }

}

 

Call Code:

PrintMatchingNumbers(1, 10, new NumberTester(IsOdd));

 

.Net 2.0时代的匿名方法

public delegate bool NumberTester(int i);

public static void PrintMatchingNumbers(int from, int to, NumberTester filter)

{

    for (int i = from; i <= to; ++i)

    {

        if (filter(i))

        {

            Console.WriteLine(i);

        }

    }

}

 

Call Code:

PrintMatchingNumbers(1, 10, delegate(int i)

{

    return (i % 2) == 1;

});

 

.Net 3.0时代的Lambda expressions(参数=> 表达式)

public delegate bool NumberTester(int i);

public static void PrintMatchingNumbers(int from, int to, NumberTester filter)

{

    for (int i = from; i <= to; ++i)

    {

        if (filter(i))

        {

            Console.WriteLine(i);

        }

    }

}

 

Call Code:

PrintMatchingNumbers(1, 10, i => (i % 2) == 1);

 

3.   LINQ是如何实现的

System.Linq 名字空间下,你会发现大量直接或间接绑定到 IEnumerable<T> 的扩展方法。也就是说 LINQ 的功能都是通过这些扩展方法实现的,而编译器负责将 LINQ 语法翻译成对这些扩展方法的调用。

4.   LINQ的组成

clip_image002

5.   LINQ开门三件事

a)         获得数据源

b)        创建查询

c)         执行查询

clip_image003

 

//  Data source.

int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

 

//  Query creation.

IEnumerable<int> numQuery =

    from num in numbers

    where (num % 2) == 0

    select num;

 

//  Query execution.

foreach (int j in numQuery)

{

    Console.Write("{0,1} ", j);

}

 

numQuery.ToList().ForEach(n => Console.WriteLine(n));

 

/*

IEnumerable<int> numQuery =

    numbers.Where(new Func<int,bool>(IsEven));

   

    numbers.Where(

        delegate(int n)

        {

            return (n % 2) == 0;

        }

    );

   

    numbers.Where(n => (n % 2) == 0);

from num in numbers where (num % 2) == 0 select num;

 

* public static bool IsEven(int n)

    {

        return (n % 2) == 0;

    }

 * */

 

6.   LINQ To Object

a)         DEMO:获取String类型的方法

(贯穿C# 3.0的特性,Lambda表达式,简单表达式,Select子句,OrderBy子句,Form子句,Where子句,GroupBy子句,对结果的去重,限制结果个数等)

MethodInfo[] methodInfos = typeof(string).GetMethods();

 

var query = from i in methodInfos

orderby i.Name

select i.Name;

 

IEnumerable<string> query = methodInfos

                .OrderBy(i => i.Name)

                .Select(i => i.Name);

 

var query = from i in methodInfos

            where i.IsPublic

            orderby i.Name

            select i.Name;

 

var query = from i in methodInfos

            where i.IsPublic

            orderby i.Name

            select new { i.Name, i.ReturnType };

 

var query = (from i in methodInfos

            where i.IsPublic

            orderby i.Name

            select new { i.Name, i.ReturnType }).Distinct();

 

var query = (from i in methodInfos

            where i.IsPublic

            orderby i.Name

            select new { i.Name, i.ReturnType }).Distinct().Take(1);

 

var query = from i in methodInfos

            where i.IsPublic

            orderby i.Name

            group i by i.Name into g

            select new {KEY = g.Key, Items = g};

 

foreach (var s in query)

{

    Console.WriteLine(s.KEY);

    foreach (var q in s.Items)

    {

        Console.WriteLine("\t{0}", q.GetParameters().Count());

    }

}

 

var query = from i in methodInfos

            where i.IsPublic

            orderby i.Name

            group i by i.Name into g

            select new { KEY = g.Key, MaxParameterCount = g.Max(p=>p.GetParameters().Count()) };

 

b)        DEMO:获取Int类型相对String所特有的方法; 获取Int类型和String的全部方法;获取Int类型和String类型的共有方法

(两个集合求差Except,求合Union,关联Join

(查询结果就是集合,集合就可以查询。查询可以嵌套)

var query = (from i in typeof(int).GetMethods()

            select i.Name).Except(

            from i in typeof(string).GetMethods()

            select i.Name

            );

 

var query = (from i in typeof(int).GetMethods()

              select i.Name).Union(

            from i in typeof(string).GetMethods()

            select i.Name

            );

 

var query = (from s in typeof(string).GetMethods()

            join i in typeof(int).GetMethods()

            on s.Name equals i.Name

            select s.Name).Distinct();

 

var query = (from s in typeof(string).GetMethods()

            from i in typeof(int).GetMethods()

            where s.Name == i.Name

            select s.Name).Distinct();

 

7.   LINQ To Relation

a)         LINQ To DataSet

借助于扩展方法 DataTableExtensions.AsEnumerable() DataTable 转换成

EnumerableRowCollection<TRow>:IEnumerable<TRow> 来实现对 LINQ 的支持。

using System.Data;

using System.Data.Common;

using System.Data.SqlClient;

 

DbProviderFactory factory = SqlClientFactory.Instance;

string connStr = ConsoleApplication1.Properties.Settings.Default.NorthwindConnectionString;

 

using (DbConnection conn = factory.CreateConnection())

{

    conn.ConnectionString = connStr;

    conn.Open();

 

    DbCommand cmd = conn.CreateCommand();

    cmd.CommandText = "select * from Customers";

 

    DbDataAdapter ad = factory.CreateDataAdapter();

    ad.SelectCommand = cmd;

 

    DataSet ds = new DataSet();

    ad.Fill(ds);

 

    var table = ds.Tables[0];

    var q = from o in table.AsEnumerable()

            where o.Field<string>("City") == "London"

            select new

            {

                Name = o.Field<string>("ContactName"),

                Phone = o.Field<string>("Phone")

            };

 

    foreach (var u in q)

    {

        Console.WriteLine(u);

    }

}

 

b)        LINQ To SQL (DLINQ)

                        i.              ORM工具

添加一个 “LINQ To SQL Classes”项(扩展名为dbml 服务管理器中拖拽

                      ii.              DataContext

NorthWindDataContext northwind = new NorthWindDataContext()

var customer = from c in northwind.Customers

               select c;

 

DataContext northwind = new DataContext(connString);

Table<Customer> customers = northwind.GetTable<Customer>();

var query = from c in customers select c;

 

                    iii.              LOG

northwind.Log = Console.Out;

 

                        i.              简单查询

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

 

    var query = from c in northwind.Customers

                orderby c.ContactName

                select c;

 

    foreach (var c in query)

    {

        Console.WriteLine("{0} {1}", c.ContactName, c.ContactTitle);

    }

}

 

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

    string city = "London";

    var query = from c in northwind.Customers

                where c.City == city

                orderby c.ContactName

                select c;

 

    foreach (var c in query)

    {

        Console.WriteLine("{0} {1}", c.ContactName, c.City);

    }

}

 

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

    string city = "London";

    var query = from c in northwind.Customers

                where c.City == city

                orderby c.ContactName

                select c;

    city = "Paris";

 

    foreach (var c in query)

    {

        Console.WriteLine("{0} {1}", c.ContactName, c.City);

    }

}

                      ii.              One to One /One to Many / Many to Many

var p = (from c in northwind.Categories

        where c.CategoryName == "Meat/Poultry"

        select c).First().Products;

 

var c = (from p in northwind.Products

        where p.CategoryID == 2

        select p).First().Category;

 

var q = from c in northwind.Categories

        from p in northwind.Products

        where c.CategoryName == "Meat/Poultry" && c.CategoryID == p.CategoryID

        select new { c.CategoryName, p.ProductName };

 

var q = from c in northwind.Categories

        where c.CategoryName == "Meat/Poultry"

        join p in northwind.Products

        on c.CategoryID equals p.CategoryID

        select new { c.CategoryName, p.ProductName };

 

                    iii.              增删改

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

 

    Product p = new Product { ProductName = "MyProduct" };

    northwind.Products.Add(p);

 

    northwind.SubmitChanges();

 

    Console.WriteLine(p.ProductID);

}

 

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

 

    Product product = (from p in northwind.Products

                where p.ProductName == "MyProduct"

                select p).First();

 

    northwind.Products.Remove(product);

 

    northwind.SubmitChanges();

}

 

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

   

    var query = (from p in northwind.Products

                where p.ProductID == 5

                select p).First();

 

    query.QuantityPerUnit = "48 boxes";

 

    northwind.SubmitChanges();

}

 

                     iv.              事务

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Connection.Open();

    northwind.Transaction = northwind.Connection.BeginTransaction();

    try

    {

        Product p = new Product { ProductName = "MyProduct2" };

        northwind.Products.Add(p);

        northwind.SubmitChanges();

 

        northwind.Transaction.Commit();

    }

    catch(Exception ex)

    {

        northwind.Transaction.Rollback();

        Console.WriteLine(ex.Message);

    }

}

                       v.              分页

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

 

    int pageIndex = 4;

    int pageSize = 10;

 

    int skipCount = (pageIndex - 1) * pageSize;

 

    var query = from c in northwind.Customers

                orderby c.ContactName

                select c;

 

    Console.WriteLine("Page {0}", pageSize);

    foreach (var c in query.Skip(skipCount).Take(pageSize))

    {

        Console.WriteLine("Name:{0} Phone:{1}", c.ContactName, c.Phone);

    }

}

 

SELECT TOP 10 [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName],

[t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode],

[t0].[Country], [t0].[Phone], [t0].[Fax]

FROM [dbo].[Customers] AS [t0]

WHERE NOT (EXISTS(

    SELECT NULL AS [EMPTY]

    FROM (

        SELECT TOP 30 [t1].[CustomerID]

        FROM [dbo].[Customers] AS [t1]

        ORDER BY [t1].[ContactName]

        ) AS [t2]

    WHERE [t0].[CustomerID] = [t2].[CustomerID]

    ))

ORDER BY [t0].[ContactName]

-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.20706.1

 

SELECT TOP 10 [t1].[CustomerID], [t1].[CompanyName], [t1].[ContactName],

[t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode],

[t1].[Country], [t1].[Phone], [t1].[Fax]

FROM (

    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ContactName]) AS [ROW_NUMBER], [t0]

.[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0]

.[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].

[Phone], [t0].[Fax]

    FROM [dbo].[Customers] AS [t0]

    ) AS [t1]

WHERE [t1].[ROW_NUMBER] > @p0

ORDER BY [t1].[ContactName]

-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [30]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1

 

                     vi.              ExecuteCommandExecuteQuery

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

    northwind.ExecuteCommand(

                "Update Employees Set Country = {0} where title = {1}",

                "USA",

                "Sales Manager"

                );

}

 

using (NorthWindDataContext northwind = new NorthWindDataContext())

{

    northwind.Log = Console.Out;

    var q = northwind.ExecuteQuery<Employee>("select * from [Employees]");

 

    foreach (var e in q)

    {

        Console.WriteLine(e.LastName);

    }

}

8.   LINQ To XML

a)         查询

var doc = XDocument.Load("NorthWindMapping.xml");

 

var query = from t in doc.Elements("Database").Elements("Table")

            where t.Attribute("Name").Value.StartsWith("C")

            select t;

 

foreach (var i in query)

{

    Console.WriteLine(i.Attribute("Name").Value);

}

 

// XML字符串生成XDocument对象

var doc = XDocument.Parse(

  @"<people>

    <person>

      <id>1</id>

      <name>user1</name>

      <age>1</age>

    </person>

  </people>");

b)        创建

var doc = new XDocument(

  new XDeclaration("1.0", "utf-8", "yes"),

  new XComment("test xml"),

 

  new XElement("Customers",

    new XElement("Customer",

      new XAttribute("title", "CEO"),

      new XElement("id", 1),

      new XElement("name", "张三"),

      new XElement("age", 36),

      new XElement("email", new XCData("<a href=\"mailto:zhangsan@XXX.com\">邮件</a>"))

    ),

 

    new XElement("Customer",

      new XElement("id", 2),

      new XElement("name", "李四"),

      new XElement("age", 28)

    )

  )

);

c)         更改

var doc = XDocument.Load("test.xml");

var query = from c in doc.Elements("Customers").Elements("Customer")

            where c.Attribute("title") != null && c.Attribute("title").Value == "CEO"

            select c;

 

foreach (var e in query)

{

    e.SetAttributeValue("title", "CEO,CTO");

}

 

var query2 = from c in doc.Elements("Customers").Elements("Customer")

             where Convert.ToInt16(c.Element("id").Value) == 2

        select c;

 

foreach (var e in query2)

{

    e.Remove();

}

 

doc.Save("test.xml");

 

9.   LINQ的性能

using System.Data;

using System.Data.Linq;

using System.Data.SqlClient;

using System.Diagnostics;

 

static public string UsingSqlReader()

{

    Stopwatch watch = new Stopwatch();

    watch.Start();

 

    using (SqlConnection conn = new SqlConnection(connString))

    {

        if (conn.State != System.Data.ConnectionState.Open)

            conn.Open();

        for (int i = 1; i <= 1000; i++)

        {

            SqlCommand cmd = new SqlCommand(

                "SELECT ProductID,ProductName FROM Products WHERE ProductID=" + i.ToString(), conn);

            cmd.CommandType = CommandType.Text;

            using (SqlDataReader reader = cmd.ExecuteReader())

            {

                if (reader.Read())

                {

                    Product p = new Product();

                    p.ProductID = (int)reader["ProductID"];

                    p.ProductName = (string)reader["ProductName"];

                }

            }

 

        }

    }

 

    watch.Stop();

 

    return "[UsingSqlReader] total time: " + watch.Elapsed.ToString();

}

 

static public string UsingLinqToSQL()

{

    Stopwatch watch = new Stopwatch();

    watch.Start();

 

    NorthWindDataContext northwind = new NorthWindDataContext();

 

    for (int i = 1; i <= 1000; i++)

    {

        Product product = northwind.Products.SingleOrDefault(p => p.ProductID == i);

    }

 

    watch.Stop();

 

    return "[UsingLinqToSQL] total time: " + watch.Elapsed.ToString();

}

 

static public string UsingOptimizeLinqToSQL()

{

    Stopwatch watch = new Stopwatch();

    watch.Start();

 

    using (SqlConnection conn = new SqlConnection(connString))

    {

        if (conn.State != System.Data.ConnectionState.Open)

            conn.Open();

 

        NorthWindDataContext northwind = new NorthWindDataContext(conn);

 

        for (int i = 1; i <= 1000; i++)

        {

            Product product = northwind.Products.SingleOrDefault(p => p.ProductID == i);

        }

    }

    watch.Stop();

 

    return "[UsingOptimizedLinqToSQL] total time: " + watch.Elapsed.ToString();

 

}

 

static public string UsingCompiledLinqToSQL()

{

    Stopwatch watch = new Stopwatch();

    watch.Start();

 

    var query = CompiledQuery.Compile(

            (NorthWindDataContext northwind, int index)

            => northwind.Products.SingleOrDefault(p => p.ProductID == index));

 

    using (SqlConnection conn = new SqlConnection(connString))

    {

        if (conn.State != System.Data.ConnectionState.Open)

            conn.Open();

 

        NorthWindDataContext northwind = new NorthWindDataContext(conn);

 

        for (int i = 1; i <= 1000; i++)

        {

            Product p = query(northwind, i);

        }

    }

    watch.Stop();

 

    return "[UsingCompiledLinqToSQL] total time: " + watch.Elapsed.ToString();

 

}

 

Console.WriteLine(UsingSqlReader());

Console.WriteLine(UsingLinqToSQL());

Console.WriteLine(UsingOptimizeLinqToSQL());

Console.WriteLine(UsingCompiledLinqToSQL());

 

Console.ReadLine();

 

Copyright © 2024 TonyChen
Powered by .NET 8.0 on Kubernetes