`

LINQ技术

阅读更多

 

LINQ(语言集成查询)技术

 

前面学习LinqDataSource时我们提起过Linq(语言集成查询)的基本概念,分类及基本原理,并且使LinqDataSource通

过DataContext来处理数据库里的数据,就像我们操作数据库数据时用GridView来绑定SqlDataSource数据源,那样不

用写一行代码仅设置一下就可完成。我们也可以自己编写代码通过实现SQL语句来完成,而ASP.NET3.5为我们提供了

LINQ也可以完成,并且LINQ真正强大的地方在于其提供了统一的语法来查询多种异构的数据源(可以只用C#或VB.NET

等.NET语言来操作不同的关系型数据库中的表(LINQ to SQL(LINQ to ADO.NET的一种,另外两种是

LINQ to Dataset(查询DataSet或DataTable内存表)和LINQ to Entities),任何实现了IEnumerable<T>,IEnumerable接口的集合,比如数组,List等(LINQ to Object),XML文档(LINQ to XML),还有一些不长用数据源(LINQ to xx))。

这些数据库表,内存表,集合,XML文档都必须直接或间接实现了IEnumerable<T>接口。LINQ to SQL中用.NET语言编写

的LINQ语句将被映射为相应的底层SQL操作。

ASP.NET3.5提供了多个与LINQ相关的命名空间System.Linq(提供支持使用LINQ进行查询的类和接口,如Enumerable类,Queryable类,IQueryable接口,IQueryable<T>接口,IOrderedQueryable接口,IOrderedQueryable接口<T>接口)System.Data.Linq(提供了与LINQ to SQL相关的类,结构,接口,枚举)System.Xml.Linq(提供了与LINQ to XML的类和枚举)。

首先我们简单学习一下用LINQ查询集合中的数据(LINQ to Object)

传统方法: 

 

   protected void Button1_Click(object sender, EventArgs e)
             {//初始化集合,这里是字符串数组
               string[] str = new string[10];
               for (int i = 0; i < str.Length; i++)
            {//字符串的PadLeft用于指定字符串的长度,如果原字符串长度不够长,用第二个字符参数在左边填充
                str[i] = i.ToString().PadLeft(2, '0');  
               }
             ArrayList List = new ArrayList();
              foreach (var item in str)
               {//获取集合中元素的序号
                int index = Int32.Parse(item.Substring(1,1));
                //如果是偶数序号则保存到ArrayList
                if (index%2==0)
                {
                    List.Add(item);
                }
               }
             //输出集合中是偶数序号的元素
             foreach (var item in List)
              {
                Label1.Text += item;
              }
               DropDownList1.DataSource = List;
               DropDownList1.DataBind();
             }

 

LINQ方法:    

 

  protected void Button2_Click(object sender, EventArgs e)
               {
                  string[] str = new string[10];
                  for (int i = 0; i < str.Length; i++)
                  {
                   str[i] = i.ToString().PadLeft(2, '0');
                  }
                  //查询
                  var result=from s in str
                      let index=Int32.Parse(s.Substring(1,1))
                      where index%2==0
                      select s;
                 foreach (var item in result)
                 {
                   Label2.Text += item;
                 }
                 DropDownList2.DataSource = result;
                 DropDownList2.DataBind();
                }

 

以上LINQ方法查询返回的result不像传统方法的List那样是个包含数据的集合,而是一个特定的LINQ对象(这里是一

个WhereIterator<T>对象,如果查询是一个联合表达式的查询则result是一个UnionIterator<T>对象,如果只是简单

查询而没有Where子句则result是一个SelectIterator<T>对象等等,这些**Iterator<T>都实现了IEnumerable<T>接口)当遍历这些对象时,它们会执行LINQ表达式进行实际的计算,除了用foreach语句遍历外,可以直接将LINQ查询绑定

到一个数据绑定控件中(如上DropDownList2控件,当然数据绑定控件也可以绑定集合如DropDownList1)。

对于其他类型LINQ查询,与LINQ to Object查询一样,都完成了如下步骤:

注:

1.创建LINQ表达式,表达式中的集合必须要直接或间接实现了IEnumerable<T>接口2.获取一个直接或间接实现了IEnumerable<T>接口的迭代对象3.当遍历对象时,LINQ开始实际的数据检索。

 

LINQ查询数据库中的数据(LINQ to SQL)

 

由于传统方法我们都比较了解,所以在此不再使用,但要注意的是传统方法是使用SQL或存储过程直接从数据库中查询

数据,而LINQ方法首先创建dbml文件,再为某个表创建实体类,然后LINQ通过数据上下文类的实例操作表的实体类从而操作了表。至于怎么创建dbml文件,表实体类及数据上下文类DataContext可以去看前面文章里关于LinqDataSource的讲解(数据上下文类就是数据库实体类,表实体类可以通过它的name属性来命名其类名,默认表实体类名就是表名。默认数据上下文类名是dbml文件名+DataContext,该类继承自System.Data.Linq.DataContext类)。现在我们就可以编写LINQ查询语句查询数据库文件里的数据了:

 

                 protected void Button3_Click(object sender, EventArgs e) {//创建见数据上下文类的实例,有中重载参数是连接字符串 MyDataDataContext datacontext=new MyDataDataContext(@"DataSource=.\SQLEXPRESS;

Initial Catalog=newsystem;Integrated Security=True"); //创建查询 var result = from comt in datacontext.comment //从comment表里查询,comment为默认表实体类名 select comt.content; //查询表里的content字段 foreach (var item in result) { Label3.Text += item; } DropDownList3.DataSource = result; DropDownList3.DataBind(); }

 

LINQ查询DataSet对象中的数据

传统方法:

 

 protected void Button4_Click(object sender, EventArgs e)

        {

            SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=newsystem;Integrated Security=True");

            SqlDataAdapter da1 = new SqlDataAdapter("select * from comment", conn);

            SqlDataAdapter da2 = new SqlDataAdapter("select * from news", conn); 

            conn.Open();

            DataSet ds = new DataSet();

            da1.Fill(ds,"123");  //将da1里查到的数据表添加到DataSet里,第二个参数123是comment表的映射

            da2.Fill(ds, "234"); //将da2里查到的数据表添加到DataSet里,第二个参数234是news表的映射

            conn.Close();

            foreach (DataRow row in ds.Tables["123"].Rows)  //遍历da的123表(comment表)的行

            {

                Label4.Text += row["content"].ToString();

            }

        }

LINQ方法:

 

 protected void Button5_Click(object sender, EventArgs e)

        {

            SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=newsystem;Integrated Security=True");

            SqlDataAdapter da1 = new SqlDataAdapter("select * from comment", conn);

            SqlDataAdapter da2 = new SqlDataAdapter("select * from news", conn);

            conn.Open();

            DataSet ds = new DataSet();

            da1.Fill(ds, "123");  

            da2.Fill(ds, "234"); 

            conn.Close();

            //LINQ查询,前面讲过,LINQ要求获得一个实现了IEnumerable<T>接口的对象,而Datatable和DataRowCollection(实现了IEnumerable接口)都没实现该接口,而DataTable.AsEnumerable()返回一个

EnumerableRowCollection的row行集合(该DataTable里的行的集合,实现了IEnumerable<T>接口)

            var result = from u in ds.Tables["123"].AsEnumerable()

                         select u;

            foreach (var u in result)

            {

                Label5.Text += u.Field<string>("content").ToString(); //DataRow.Field<T>用于强类型化

            }

        }

 

 

LINQ查询XML文件(LINQ to XML)

传统方法(需要书写准确且高效的XPath对开发人员是一个技术挑战,而且往往要知道XML文件的具体结构):

       string xmlstring = "<shouye id='shouye' title='首页'>"+ "<diyi id='diyi' title='第一页'>"+ "<diyi0 id='diyi0' title='第一页1'>足球</diyi1>"+ "<diyi0 id='diyi0' title='第一页2'>篮球</diyi2>"+ "</diyi>"+ "<diyi id='diyi' title='第一页'>" + "<diyi1 id='diyi1' title='第一页1'>手球</diyi1>" + "<diyi2 id='diyi2' title='第一页2'>水球</diyi2>" + "</diyi>" + "<dier id='dier' title='第二页'>"+ "<dier1 id='dier1' title='第二页1'>排球</dier1>"+ "<dier2 id='dier2' title='第二页2'>网球</dier2>"+ "</dier>"+ "</shouye>";

            protected void Button6_Click(object sender, EventArgs e)

             {    创建XmlDocument类的实例,using System.Xml;

               XmlDocument xmldoc = new XmlDocument();

                  将XML结构的字符串通过LoadXml()导入到该实例

               xmldoc.LoadXml(xmlstring);

                  创建查询XML文件的XPth

           string xpath = "/shouye/diyi";

将想查询的节点名写入XPath字符串,子节点的话要从根节点写起通过SelectNodes()方法获得与该节点名相同节点的的集合,每个节点的类型是XmlNode,该例子会获得俩节点(名字是diyi的节点有俩)

            XmlNodeList nodes = xmldoc.SelectNodes(xpath);

               //在遍历这俩节点

            foreach (XmlNode node in nodes)

            {//遍历这俩节点的子节点(将会得到diyi0,diyi0,diyi1,diyi1这四个节点)

               foreach (XmlNode childnode in node)

                {//InnerXml与InnerText都获得节点值,它们的区别与innerHtml和innerText一样,

                 //Attributes["属性名"].Value获得节点的某个属性的值

                  Label6.Text +=childnode.InnerXml+childnode.Attributes     ["id"].Value+childnode.InnerText;

                }

            }

        }

LINQ to XML方法:         

                protected void Button7_Click(object sender, EventArgs e)

                 {//导入XML文件,using System.Xml.Linq;

                   XElement xmldoc = XElement.Parse(xmlstring);

               //查询diyi的子节点,Elements("节点名,比如是XX")方法用于获取节点XX的子节点的集合

                   var result = from u in xmldoc.Elements("diyi")

                       //select u;

                  //在diyi的子节点集合中查找节点名是diyi1的节点(Element("节点名")获取这样的节点名的节点)

                       select u.Element("diyi1");

                  foreach (var node in result)

                  {//这里var代表XElement类型的节点,这种类型节点与XmlNode类型节点不同,属性Value获得节点值,Attribute("属性名").Value获得属性值

                   Label7.Text += node.Value+node.Attribute("id").Value;

                  }

                 }

可以看出LINQ to XML查询XML不需要知道XML文件的结构(主要体现在不使用XPath上)

 

 

前面讲了几个简单的LINQ查询的例子,下面我们来学习一下C#3.0引入的新的语言机制(隐型局部变量,对象初始化器,

集合初始化器,匿名类型,隐型数组,Lambda表达式,查询表达式等),这些语言机制为LINQ提供了语法支持:

1.使用var创建隐型局部变量(这在上面的例子中多次使用过)

声明变量int,string[],UserInfo(用户自定义类型)

在C#1.02.0中,必须指定一个变量的数据类型:

int i=20;string[] s=new string[2];UserInfo ui=new UserInfo();

在C#3.0中: var i=20;var s=new string[]{"C#","java"};var ui=new UserInfo(); 编译器会自动推断数据类型

var关键字可以在以下4种情况下使用:

①var i=2;

②for(var i=0;i<100;i++){}

③string[] strs=new string[]{"C#","java"};

foreach(var str in strs){}

④using(var file=new StreamReader("C:\\file.txt")){}

以下4中情况下不能用var声明隐型局部变量

①var i;(没有初始化器,且初始化器必须为表达式) ②var i=i+1;(初始化器不能包含自身对象) ③var i=null;(初

始化值不能为null) ④不能在同一语句中初始化多个隐式类型的变量

2.对象初始化器(可以不调用类的构造函数就能创建类的实例,并设置该实例的属性的值)

在C#1.02.0中,创建一个对象往往需要调用类的构造函数,并在构造函数中初始化该对象的值。

在C#3.0中,创建一个对象不需要调用类的构造函数,并设置该对象的各个属性值:

Person pr = new Person { i = 1, s = "对象初始化器"};

在LINQ查询表达式中,使用对象初始化器可以在select子句中创建新的对象:

 public class Person

    {

        public int i { get; set; }

        public string s { get; set; }

    }

 protected void Button9_Click(object sender, EventArgs e)

        { List<>要求using System.Collections.Generic;数组和List都实现了IEnumerable<T>接口

          List<Person> list = new List<Person>();

            for (int j = 0; j < 3; j++)

            {

                list.Add(new Person { i = j, s = j.ToString() + "XXX" }); //用到了对象初始化器

            }

            var result = from u in list

                         where u.i < 4

                         select new Person {i=u.i}; 用到了对象初始化器,创建了一个新对象

            foreach (var item in result)

            {

                Label9.Text += item.i;

            }

        }

 

 

3.集合初始化器(用来初始化一个集合,他由一系列元素组成,并封闭于{}标记内)

如List<int> number=new List<int>{0,1,2,3,4,5};

使用集合初始化器:         

                           public class Person

                            {

                              public int i;

                              public List<string> list;

                              public Person(int j, List<string> s)

                              {

                               i = j; list = s;

                              }

                            }

                   protected void Button10_Click(object sender, EventArgs e)

                    {

                      List<Person> list=new List<Person>();

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

                       {

                list.Add(new Person(i, new List<string> {"123","456"})); //用对象初始化器初始化了第二 

                                                                                                             个类型是List<string>的参数

                       }

                     var result = from u in list

                         where u.list[0] == "123"  //public int i;public List<string> list;(可以给这

                                                                                                                    字段加属性就不用声明为public了)

                         select u.i;

                     foreach (var item in result)

                     {

                       Label10.Text += item;

                     }

                    }

 

 

4.匿名类型(它使用new操作符和对象初始化器能创建一个匿名类型的对象)

如:var person=new {I=1,S="C#"};   I,S是匿名对象的属性(这段代码等同于下面的代码)

在创建匿名类型的对象时,编译器先创建一个类并为该类创建相应属性,然后为该类创建一个实例并且为属性赋值:

class _Anonymous1

{

  private int i;private string s;

  public int I{return i;i=value;}

  public string S{return s;s-value;}

}

var person=new _Anonymous1(); person.I=1;person.S="C#";

使用匿名类型的对象(LINQ中当select子句需要输出一种新的表现形式的结果时,可以使用匿名类型创建一个新对象,

而并不需要定义该对象的相关的类):

                           public class Person

                           {

                            public int i { get; set; }

                            public string s { get; set; }

                           }

                     protected void Button11_Click(object sender, EventArgs e)

                     {

                       List<Person> list = new List<Person>();

                       for (int j = 0; j < 10; j++)

                       {

                        list.Add(new Person { i = j, s = "123" });

                       }

                       var result=from u in list

                                                   使用匿名类型创建一个新对象

    select new { 匿名类型对象的属性1 = u.i, 匿名类型对象的属性2 = u.s, 匿名类型对象的属性3="C"};

                       foreach (var item in result)

                       {

                        Label11.Text += item.ToString();

                       }

                      }

 

 

5.隐型数组(隐型数组与匿名类型很像,其由var关键字和数组初始化器创建(一种集合初始化器),不过{}中的元素不

能为null,且这些元素必须能够隐式转换为同一种数据类型)

如:var numbers=new[]{1,2,3,4,5};var strs=new[]{"java","C#"};但var errors=new[]{1,2,"java"};是错误的

6.Lambda表达式(是一种更精简的匿名函数,可以包含表达式和语句,并且可用于创建委托或表达式目录树类型)

Lambda表达式的基本形式如下: (输入参数(可无))=>表达式或语句块  如:(x)=>x*x ()=>response.write("C#")

(x,y)=>x+y 语句块的形式:(x,y)=>{int result=x*y;response.write(result.ToString());}

既然说到匿名函数就不得不提一下委托:              事件与委托  

委托类似于C/C++里的函数指针,它指向一个函数,在C#里我们可以将其理解为委托类Delegate(抽象类,不能实例化)

的派生类的对象的引用,我们可以这样来声明这些派生类:Public delegate int MyFristDelegate(int i);可以看出

与一般的类的声明不同,委托类的派生类有返回值和参数。然后我们就可以给该类创建实例了:

MyFristDelegate mfd=new MyFristDelegate();和普通类一样委托类的派生类也可以有构造函数,而我们可以在后面

的()里指定该构造函数(只写函数名)只不过该构造函数不是在实例化时执行,而是在使用实例时执行(如下文的

mdf(1)):MyFristDelegate mfd=new MyFristDelegate(Hanshu);

注意这个函数的返回值的类型和参数的类型和数量必须与声明委托类的派生类时的一样:

public int Hanshu(int j){};

还有一种实例化的方式可以将没有声明的函数(匿名函数)作为该委托类的派生类的构造函数(直接把函数体在实例化时写上):

MyFristDelegate mfd=delegate(int j){这里函数体的返回值类型必须是int型};

我们要用的时候就把委托类的派生类的实例看成一个方法那样用:mdf(赋值),它的返回值就是那个构造函数的返回值

声明委托类的派生类Public delegate int MyFristDelegate(int i);在函数或事件外,在类里

给委托类的派生类创建实例MyFristDelegate mfd=new MyFristDelegate(Hanshu);或MyFristDelegate 

mfd=delegate(int j){这里函数体的返回值类型必须是int型};可以在类里,也可以在函数或事件内:

匿名函数:

 public partial class _Default:System.Web.UI.Page

 {

   Public delegate int MyFristDelegate(int i);

   MyFristDelegate mfd=delegate(int j){这里函数体的返回值类型必须是int型};

   protected void Button13_Click(object sender, EventArgs e)

     {

         MyFristDelegate mfd=delegate(int j){这里函数体的返回值类型必须是int型};

         label13.text=mdf(1);

     } 

  }

命名函数:

 public partial class _Default:System.Web.UI.Page

 {

    Public delegate int MyFristDelegate(int i);

    MyFristDelegate mfd=new MyFristDelegate(Hanshu);

    protected void Button13_Click(object sender, EventArgs e)

     {

         MyFristDelegate mfd=new MyFristDelegate(Hanshu);

         label13.text=mdf(1);

     } 

    private int Hanshu(int i)

    {这里函数体的返回值类型必须是int型};

  }

Lambda表达式:(我们可以把lambda表达式当作匿名方法那样来用,即委托类的派生类的引用指向lambda表达式,像匿

名函数一样,下文的MyFristDelegate mfd=(x)=>x*x;可以在类里,也可以在函数或事件内)

 

lambda表达式里的参数不需指定类型,但其数量要与MyFristDelegate()里参数数量相同,mdf()里传入参数的类型数量都要与MyFristDelegate()里参数的类型数量相同,返回值类型由lambda表达式=>后面的决定,本例要与 int MyFristDelegate()的返回值类型相同

 public partial class _Default:System.Web.UI.Page

 {

   Public delegate int MyFristDelegate(int i);

   MyFristDelegate mfd=(x)=>x*x;

   protected void Button13_Click(object sender, EventArgs e)

     {

         MyFristDelegate mfd=(x)=>x*x;

         label13.text=mdf(1);

     } 

  }

 

 

7.查询表达式(在前面的学习中我们用到了一些查询表达式的基本子句,像from,where,select。现在我们来看看这些查询表达式的基本子句):

from(指定查询操作的范围变量和数据源)查询表达式必须以from开头

如:from u in xxx  u是范围变量(一般指源序列中的每一个元素)  xxx是数据源(类型一般要为IEenumerable,IEenumerable<T>或它们的派生类型)

如果含有子查询,那么子查询也必须以from开头

如果数据源的类型是非泛型IEenumerable类型(如ArrayList等)时,则查询时必须显式指定范围变量的数据类型:

 

 protected void Button14_Click(object sender, EventArgs e)

        {

            ArrayList array = new ArrayList();

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

            {

                array.Add(i);

            }

            var result = from int u in array

                         where u < 5

                         select u;

            foreach (var item in result)

            {

                Label14.Text += item.ToString();

            }

        }

复合from子句查询

如果在数据源的每个元素中还包含一个数据源,则可以用复合from子句查询:

 

  public class Person

    {

        public int i { get; set; }

        public List<string> list { get; set; }

    }

 

  protected void Button15_Click(object sender, EventArgs e)

        {

            List<Person> list = new List<Person>();

            for (int j = 0; j < 10; j++)

            {使用了对象初始化器,对象里面的一个属性仍旧是一个数据源

                list.Add(new Person{i=j, list=new List<string>{j.ToString()+"C#"}});

            }

            var result = from u in list

                         from n in u.list

                         where u.i < 5 && int.Parse(n.Substring(0,1))> 3

              使用了匿名类型,可以不用写属性select new { 属性1=u.i,属性2=n };

                         select new { u.i, n };

            foreach (var item in result)

            {

                Label15.Text += item.ToString();

            }

        }

多个from子句查询

当有多个互相独立的数据源时,可以使用多个from子句查询所有的数据源中的数据

 

 public class People

    {

        public int i { get; set; }

        public string s { get; set; }

    }

 

 protected void Button16_Click(object sender, EventArgs e)

        {

            List<People> list1 = new List<People>();

            List<People> list2 = new List<People>();

            for (int j = 0; j < 10; j++)

            {

                list1.Add(new People { i = j, s = "C#" });

                list2.Add(new People { i = j, s = "java" });

            }

            var result = from u in list1

                         from n in list2

                         where u.i < 5 && n.i > 5

          创建匿名类型对象时写上属性名能避免相同的属性引起的编译错误

                         select new { I1=u.i,I2=n.i};

            foreach (var item in result)

            {

                Label16.Text += item.ToString();

            }

        }

select(筛选元素的逻辑条件)group(对查询结果进行分组)查询表达式必须以select或group结束

where(指定查询结果的类型和表现形式)

group(对查询的结果进行分组)

into(提供一个可以引用jion,group,select的操作结果的标识符)

 

public class Person

    {

        public int i { get; set; }

        public string s { get; set; }

        public override string ToString()  重写了ToString()方法,以后输出该类对象就会输出i.ToString()+s

        {

            return i.ToString()+s;

        }

    }

 

  protected void Button17_Click(object sender, EventArgs e)

        {

            List<Person> list = new List<Person>();

            for (int j = 0; j < 7; j++)

            {

                list.Add(new Person { i=j,s=j.ToString()+"奇偶分组"});

            }

            var result = from u in list

                         group u by u.i % 2 == 0 into g 按u.i是偶数分组并将分组结果用into子句保存到g(g就包含了偶数集合跟奇数集合俩集合,类型为IGrouping<bool,Person>)

                         where g.Count() == 4  

                         select g;   选出集合中元素个数是4的集合(这里是偶数集合)--鼠标移到这,可以看出g的类型是   IGrouping<bool,Person>

            foreach (var item in result)  --鼠标移到这,可以看出result的类型是IEnumerable<IGrouping<bool,Person>>

            {

                foreach (var n in item) --鼠标移到这,可以看出item的类型是IGrouping<bool,Person>

                {

                    Label17.Text += n.ToString();

                }

            }

        }

group子句对结果进行分组,并且每个组都返回一个类型为IGrouping<键的类型,值的类型>的集合(这里集合的类型是IGrouping<bool,Person>就是被分组的元素组成的集合的类型,分几组就有几个类型是IGrouping<bool,Person>的集合),into子句使g保存了这些集合。这里var result得到的是IEnumerable<IGrouping<bool,Person>>(这里只包含一个集合(偶数元素集合)),其实每个LINQ表达式都会返回一个IEnumerable<某种类型>的集合,某种类型就是group或select后面的集合的类型,foreach (var item in result)语句后得到偶数元素组IGrouping<bool,Person>(奇数元素组的集合类型也为IGrouping<bool,Person>,只不过奇数组被where子句过滤掉了),最后 foreach (var n in item)遍历偶数元素组IGrouping<bool,Person>里的每个元素。

orderby(对查询结果进行升序或降序排列,默认为升序,降序要在后面加关键字descending)

join(连接多个查询操作的数据源)

 

join子句可以设置两个数据源之间的关系。当然这两个数据源之间必须存在相关联的属性或值。

内部联接(与sql里的inner join差不多):

 public class User

    {

        public int i { get; set; }

        public string s { get; set; }

        public override string ToString()

        {

            return i.ToString()+s;

        }

    }

    public class Role

    {

        public int i { get; set; }

        public List<string> list { get; set; }

    }

  protected void Button18_Click(object sender, EventArgs e)

        {

            List<User> user = new List<User>();

            List<Role> role = new List<Role>();

            for (int j = 0; j < 10; j++)

            {

                user.Add(new user { i = j, s = "内部联接user" });

            }

            for (int k = 6; k < 10; k++)

            {

                role.Add(new Role { i = k, list=new List<string> {"内部联接role"} });

            }

            var result = from u in user

                         where u.i > 7

                         join r in role on u.i equals r.i 查询user的i大于7且与r.i相等的元素

                         select u;  u的类型是User,LINQ表达式返回给result的是类型为IEnumerable<User>的集合,我们直接遍历就可以得到类型为User的元素,而上面group的例子中经过这次遍历得到的是IGrouping<>的集合元素,所以还要再次遍历才能得到最终类型的元素,对于不清楚遍历后类型的情况,可以将鼠标移到位置上看是什么类型,然后决定是否还需要一次遍历。

            foreach (var item in result)  --鼠标移到这里,看出类型是IEnumerable<User>的集合,遍历后得到的元素的类型将是User,是最终类型,因此不需要再次遍历。

            {

                Label18.Text += item.ToString();

            }

        }

 

分组联接(在join子句后面加上into就成了分组联接,在join子句后面加上into的含义与select和group by后面加上into不同,虽然也是分组,但into g赋给g的集合不是所有的集合,而只是第2个集合(这里是role)并且集合里的元素只是符合条件的那几个元素(这里条件是u.i equals r.i)而第1个集合(这里是user)里的元素是全部元素(如果输出的话会得到第1个集合里的全部元素))http://www.tzwhx.com/newOperate/html/1/11/116/19182.html:

 protected void Button19_Click(object sender, EventArgs e)

        {

                List<对象初始化器> user = new List<对象初始化器>();

                List<复合from子句查询> role = new List<复合from子句查询>();

                for (int j = 0; j < 10; j++)

                {

                    user.Add(new 对象初始化器 { i = j, s = "内部联接user" });

                }

                for (int k = 8; k < 12; k++)

                {

                    role.Add(new 复合from子句查询 { i = k, list = new List<string> { "内部联接role" } });

                }

                var result = from u in user

                             join r in role on u.i equals r.i into g

                             select g;

                foreach (var item in result)

                {

                    foreach (var r in item)

                    {

                        Label19.Text += r.i.ToString() + r.list[0].ToString();

                    }

                }

            }

左外联接(与分组联接差不多,只不过对into g的g使用了g.DefaultIEmpty()方法,将指定该元素的默认元素)

http://blog.sina.com.cn/s/blog_46e9573c01014fx2.html

let(该关键字可以创建一个新的范围变量,并且用您提供的表达式的结果初始化该变量)

 

 protected void Button21_Click(object sender, EventArgs e)

        {

            string[] strs = new string[] { "C#","C++","Java"};

            var result = from u in strs

                         let length = 3

                         where u.Substring(0, 1) == "C" && u.Length == length

                         select u;

            foreach (var item in result)

            {

                Label21.Text += item;

            }

        }

 

 

http://www.linqpad.net/(LinqPad主页)

http://www.infoq.com/cn/news/2009/02/linqpad

http://www.cnblogs.com/lyj/archive/2008/04/17/1158509.html(LinqPad)

http://www.cnblogs.com/jams742003/archive/2010/05/05/1728124.html(LinqPad使用)

http://www.cnblogs.com/lazybee/archive/2008/01/24/1051950.html(C# 3.0 之新特性总结)

http://www.cnblogs.com/lsxqw2004/archive/2009/10/14/1583539.html(委托,匿名函数,Lambda表达式)

http://www.cnblogs.com/luckeryin/archive/2010/02/09/1666368.html(委托,匿名函数,Lambda表达式|荐)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics