ASP.NET-Entity Framework学习

ASP.NET-Entity Framework学习

学习过程来源bilibili,附链接:Entity Framework实践



一、委托

1.委托的概述与声明

  • 委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。
  • 可以通过委托实例调用方法。也可以使用委托将方法作为参数传递给其他方法。
  • 委托的使用将大大提高程序的可扩展性。
  • 委托的声明决定了可由该委托引用的方法。委托可指向一个与其具有相同签名的方法:

声明语法

public delegate <返回值类型> <委托名> <参数列表>

示例

public delegate string TestDelegate(string s)

这里就是声明了一个string类型,带有一个参数的委托类型TestDelegate

能被委托调用的方法要满足条件:

  • 方法的返回值类型必须和委托定义的一致。
  • 方法的参数类型、个数和顺序必须和委托定义的一致。
  • 大部分时候被委托执行的方法是static类型的

下面是一个示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        //定义一个委托类型
        public delegate string Dele(string name);

        static void Main(string[] args)
        {
            //实例化委托方法1,new时必须指定委托方法名
            Dele d1 = new Dele(Show1);
            //实例化委托方法2,直接赋值需要委托的方法名
            Dele d2 = Show1;
            //通过委托执行方法,方法1
            d1("张三");
            //通过委托执行方法,方法2
            d2.Invoke("王五");
        }

        //测试方法1
        public static string Show1(string name)
        {
            Console.WriteLine("你好,{0}",name);
            return name;
        }
    }
}

运行结果:
运行结果


上面示例代码的深入一

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        //定义一个委托类型
        public delegate int Dele(int x);

        static void Main(string[] args)
        {
            //实例化委托
            Dele d = Cacl;
            //通过委托执行方法
            int result1=d(2);
            //修改委托绑定的方法
            d = CaclA;
            //通过委托执行方法,方法2
            int result2 = d(2);
            Console.WriteLine("{0},{1}", result1, result2);
        }

        //测试方法1
        public static int Cacl(int x)
        {
            return x*x;
        }
        //测试方法2,箭头函数,等效于Cacl方法
        public static int CaclA(int x) => x * x*x;
    }
}

运行结果:
在这里插入图片描述


上面的示例代码深入二

将委托作为参数传递,在方法中调用委托方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    //定义一个委托类型,此处放在类外面作为全局类型
    public delegate int Dele(int x);
    class Program
    {
        static void Main(string[] args)
        {
            int[] v = { 1, 2, 3 };
            //实例化委托,并委托方法
            Dele d = Square;
            //d=Cube;//修改委托的方法,达到不修改源程序,让数组结果变化的目的
            Util.Show(v, d);
            //打印数组的值
            for (int i = 0; i < v.Length; i++)
            {
                Console.WriteLine(v[i]);
            }
        }

        //计算平方的方法
        public static int Square(int x) => x * x;
        //计算立方的方法
        public static int Cube(int x) => x * x * x;
    }

    class Util
    {
        /// <summary>
        /// 一个带委托参数的方法
        /// </summary>
        /// <param name="values">数组</param>
        /// <param name="d">委托参数</param>
        public static void Show(int[] values,Dele d)
        {
            for(int i=0;i<values.Length;i++)
            {
                //修改每一个元素的值,通过调用委托方法
                values[i] = d(values[i]);
            }
        }
    }
}


运行结果:
在这里插入图片描述


2.多播委托

所有的委托实例都具有多播的能力,一个实例可以引用多个目标方法。
注意: 委托的调用顺序和它们定义的顺序是一致的,也就是说先执行第一个委托的方法,紧接着依次执行委托的方法。

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    //定义一个委托类型,此处放在类外面作为全局类型
    public delegate int Dele(int x);
    class Program
    {
        static void Main(string[] args)
        {
            //实例化委托,并委托第一个方法
            Dele d = Square;
            //委托第二个方法
            d += Cube;
            //执行委托
            d(2);
        }

        //计算平方的方法
        public static int Square(int x)
        {
            Console.WriteLine("平方方法被执行");
            return x * x;
        }
        //计算立方的方法
        public static int Cube(int x)
        {
            Console.WriteLine("立方方法被执行");
            return x * x * x;
        }
    }
}

运行结果:
在这里插入图片描述

注意: 多播委托调用的方法的返回值是最后一个委托方法的返回值,可以自行输出上面示例代码委托方法的返回值。

案例:利用委托,设计方法method1实现计算长方形的周长,method2实现计算长方形的面积,通过委托两个方法同时计算出周长和面积。

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    //定义一个委托类型,此处放在类外面作为全局类型
    public delegate void Dele(int w,int h);
    class Program
    {
        static void Main(string[] args)
        {
            //实例化委托,并委托计算周长的方法和计算面积的方法
            Dele d = Method1;
            d += Method2;
            //执行委托
            d(3,4);
        }

        /// <summary>
        /// 计算周长
        /// </summary>
        /// <param name="w">宽</param>
        /// <param name="h">高</param>
        /// <param name="perimeter">周长,引用参数</param>
        public static void Method1(int w,int h)
        {
            Console.WriteLine("周长:{0}", (w + h) * 2);
        }
        /// <summary>
        /// 计算面积
        /// </summary>
        /// <param name="w">宽</param>
        /// <param name="h">高</param>
        public static void Method2(int w, int h)
        {
            Console.WriteLine("面积:{0}", w * h);
        }
    }

}

运行结果:
在这里插入图片描述

二、匿名方法

匿名方法顾名思义,就是没有名字的方法。
匿名方法 提供了一种传递
代码块作为委托参数==的技术,匿名方法是没有名称只有主体的方法。在匿名方法中不需要指定返回类型,它是从方法主体内的return语句推断的。

匿名方法既然没有名字,也就是说在别的地方没有办法通过名字来调用这个方法,所以匿名方法一般只用一次。创建匿名方法的前提就是你要把它放到一个委托里面。
注意:匿名方法的返回值由return的结果自行推断。

匿名方法的语法结构:

  1. 先定义并实例化一个委托
    public delegate int Dele(int x, int y);
  2. 定义匿名方法
    delegate(形参列表){ return 返回值; }

下面展示一个委托的匿名方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    //定义一个委托
    public delegate int Dele(int x, int y);
    class Program
    {
        static void Main(string[] args)
        {
            //委托一个有名字的方法
            Dele d = Cacl;
            int result=d(4, 5);
            Console.WriteLine(result);

            //下面委托一个匿名方法
            //定义一个委托,未实例化
            Dele d1;
            //给委托赋值一个匿名方法
            d1 = delegate (int x,int y)
            {
                //同普通方法体一样,执行语句放在大括号里面
                return (x + y) * 2;
            };
            //执行委托方法
            result = d1(4,5);
            Console.WriteLine(result);
        }

        static int Cacl(int x,int y)
        {
            return (x + y) * 2;
        }
    }
}

运行结果:
在这里插入图片描述
不难发现这个委托方法既然没有名字,那么只能通过委托的方式来调用。

三、隐式类型

匿名类:直接new出来一个{}的对象,编译器会自动命名一个类型给这个类。
声明格式:
var 变量名=new {属性1=值,属性2=值...};

1.隐式类型的局部变量

在C#3.0中,引进了一个新的关键字叫做var,var允许你声明一个新变量,它的类型是从用来初始化变量的表达式里隐式的推断出来的,即在声明的时候,你不需要给它定义类型,它会根据它的初始化器表达式来推断出它的类型,因此,我们称它为隐式类型。

注意:为了保证使用var关键字进行声明的变量的强类型特征,C#3.0要求必须对变量初始化,并且放到同一行,同样也不能为null

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //定义两个属性一样,值不一样的匿名类
            var a = new { age = 12, name = "w" };
            var b = new { age = 13, name = "h" };
            //定义一个属性一样,但顺序不一样的匿名类
            var c = new { name="v",age = 13};
            Console.WriteLine(a.GetType());
            Console.WriteLine(b.GetType());
            Console.WriteLine(c.GetType());
        }
    }
}

运行结果:
在这里插入图片描述
注意输出结果,属性位置不一样了,编译器分配的匿名类的名字也就不一样了。

2.隐式类型的数组

和隐式类型的局部变量一样,使用var关键字来替代数组类型,有了这个特性,将使我们创建数组的工作变得更加简单。我们可以直接使用"new[]"关键字来声明数组,后面跟上数组的初始化列表。在这里,也不行需要直接指定数组的类型,数组的类型是由初始化列表推断出来的。

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program1
    {
        static void Main(string[] args)
        {
            //int[]
            var a = new[] { 1, 10, 100 };
            //string[]
            var b = new[] { "1", "2", "3" };
            //int型交错数组
            var c = new[] {
                new[] { 1, 10, 100 },
                new[] { 1, 10, 100 }
            };
            Console.WriteLine(a.GetType());
            Console.WriteLine(b.GetType());
            Console.WriteLine(c.GetType());
        }
    }
}

运行结果:
在这里插入图片描述

四、Lambda表达式

定义:Lambda表达式实际上就是一种匿名函数,在Lambda表达式中可以包含语句以及运算符等操作,并且可用于创建委托或表达式目录制类型,支持带有可绑定到委托或表达式树的输入参数的内联表达式。使用Lambda表达式可大大减少代码量,使得代码更加的优美、简洁,更有可观性。

1.Lambda表达式的表现形式

表达式形式:(参数列表)=>表达式(或代码块)。在表达式左侧表示输入参数,右侧为响应的运算语句或者判断语句等,可包含函数调用等复杂方式。运算符=>读作goes to。
注:Lambda表达式对于编写Linq查询表达式特别有用,后面就会体验到

注:左边参数列表可以有多个参数,一个参数,或者无参数,参数类型可以隐式或者显式,参数类型可以忽略,因为可以根据使用的上下文进行推断而得到。
仅当Lambda只有一个输入参数时,括号才是可选的,否则括号是必须的。

例如:

(x,y)=>x*y           //多参数,隐式类型=>表达式
x=>x*10              //单参数,隐式类型=>表达式
x=>{return x*10;}     //单参数,隐式类型=>语句块
(int x)=>x*10        //单参数,显式类型=>表达式
(int x)=>{return x*10;}  //单参数,显式类型=>语句块
()=>Console.Write(x)    //无参数

2.Lambda表达式与委托类型

如下面的示例所示,你可以将此表达式分配给委托类型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        public delegate double Del(double r);
        static void Main(string[] args)
        {
            double vResult;
            Del d1;
            //匿名方法的返回值和形参要和Del委托是一致的
            d1 = r => (4 / 3) * 3.14 * r * r * r;
            //上面代码等价于下面的匿名方法
            //d1 = delegate (double r)
            //{
            //    return (4 / 3) * 3.14 * r * r * r;
            //};
            vResult = d1(4.4);
            Console.WriteLine(vResult);
        }
    }
}

运行结果:
在这里插入图片描述

五、扩展方法

C#扩展方法:

  1. 方法所在的类必须是静态
  2. 方法也必须是静态的
  3. 方法的第一个参数必须是你要扩展的那个类型,比如要给int类型扩展一个方法,那么第一个参数就必须是int。
  4. 第一个参数前面还需要有一个this关键字

扩展方法有以下几点总结:

  1. 可以向类中添加新方法,而不需要使用继承来创建新类,也不需要修改原有的类;
  2. 如果扩展方法与类中的方法有相同的签名,则扩展方法不会被调用,即:扩展方法会被被扩展类的同名方法覆盖,所以实现扩展方法我们需要承担随时被覆盖的风险(例如:如果扩展一个
    string类中的ToString()。这时候扩展方法是无效的);
  3. 扩展方法不能访问被扩展类的私有成员;
  4. 扩展方法只能使用实例来调用,不能像普通的静态方法一样使用类名调用;
  5. 只有引入扩展方法所在的命名空间后,扩展方法才可以使用;

现需要给一个类添加一个新方法,而不通过继承,这里我们就使用扩展方法来实现,以下是一个示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Student s = new Student();
            s.Name = "小明";
            s.Run();
            s.ShowName(s);
        }
    }

    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public bool Gender { get; set; }
        public void Show()
        {
            Console.WriteLine("我喜欢表演!");
        }
    }

    /// <summary>
    /// 这是放置扩展方法的静态类
    /// </summary>
    public static class StudentEx
    {
        /// <summary>
        /// 扩展方法
        /// </summary>
        /// <param name="stu">该参数用于指明为哪个类提供的,参数前面必须使用this关键字</param>
        public static void Run(this Student stu)
        {
            Console.WriteLine("我会跑步!");
        }

        public static void ShowName(this Student stu,Student s)
        {
            Console.WriteLine("我的名字是{0}", s.Name);
        }
    }
}

运行结果:
在这里插入图片描述

:此示例代码可以看到扩展方法中有一个形参,而调用该扩展方法时,我们没有指明实参,是因为this关键字是指明该方法是提供给谁的,所以调用时是不需要该参数的。

六、yield关键字

yield关键字的作用是将当前集合中的元素立即返回。

  1. 返回元素用yield return;(一次一个的返回)。
  2. 结束返回用yield break;(终止迭代)当产生集合>达到某种条件的时候使用yield break,以终止继续创建集合
  3. 返回类型必须为lEnumerable、lEnumerable< T>、IEnumerator或IEnumerator< T>。lEnumerable枚举数,提供给在集合中进行数据的迭代,可以看做是一个集合。
    迭代的意思是对于一个集合,可以逐一取出元素并遍历之。

下面通过一个简单的示例来理解一下yield关键字的用法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建一个商品的集合
            IList<Goods> list = new List<Goods>()
            {
                new Goods(){Name="薯条",Price=7.5},
                new Goods(){Name="可乐",Price=3},
                new Goods(){Name="鸡米花",Price=8},
                new Goods(){Name="汉堡",Price=10},
                new Goods(){Name="雪碧",Price=3}
            };

            //var 可用显式类型IEnumerable<Goods>替换
            var obj = GetGoods(list, 5);
            Console.WriteLine("超过5块的商品有:");
            foreach(var item in obj)
            {
                Console.WriteLine(item.Name);
            }
        }

        /// <summary>
        /// 返回指定集合中满足条件的对象集合,这个集合是IEnumerable类型的,并且可以进行迭代
        /// </summary>
        public static IEnumerable<Goods> GetGoods(IList<Goods> list,double price)
        {
            foreach(var item in list)
            {
                if(item.Price>price)
                {
                    //遍历集合中的元素,将价格大于price的元素返回
                    yield return item;
                }
            }
        }
    }

    /// <summary>
    /// 商品类
    /// </summary>
    public class Goods
    {

        public string Name { get; set; }
        public double Price { get; set; }
    } 
}

运行结果:
在这里插入图片描述

在这做下说明:
通过以上代码可以看出yield关键字要配合IEnumerable类型进行使用,使用yield return 时,会把正在遍历的集合中的元素一个一个的返回到IEnumerable类型的集合中;使用yield break时,则停止返回,可以理解为循环中的跳出循环。

七、LINQ查询

1.什么是LINQ

Sql:通过数据库查询语句实现的数据库查询,缺点是开发效率低。
LINQ:实现在C#环境中直接通过linq语句实现对数据库的操作,通过编译器将linq语句编译成为底层的sql语句执行,提高了开发效率,更方便。
LINQ是指“语言集成查询”,其英文是指“Language Intergrated Query”。在C#中的LlNQ主要是指C#支持、实现的一种查询数据语法(及数据查询功能),这种数据查询语法的特点是,可以使用相同的语法访问不同的数据类型。
对于一个查询,如从一个List< T >集合中找出T的某个属性符合某一条件的所有元素的集合,可以使用List< T >的FindAll方法,或者直接遍历集合进行查询,也可以使用LINQ进行查询。LINQ的基本语法规范。
注意一个Linq表达式只是定义了一个查询,但是并未执行,执行时间:当时通过foreach或者for循环执行Linq时才真正执行了linq表达式,这叫延迟加载。如果想立即查询,则只需要将整个linq表达式通过数据转换方法,转换为集合或数组,就会得到查询后的结果。


首先,一个LINQ查询:

var names = new List<string> { "Nic"", ""Jason", "Linda", "Linus","Nic"};
var query = from p in names
			where p == "Nic"
			select p;
foreach(var obj in query){
	Console.Writeline(obj);//输出两行"Nic"
}

这里的 LINQ查询是从 names集合中,找出所有等于"Nic"的元素。这里query是一个lEnumerable(在这里,T是string型)型变量,frome p in names是一个from子句,where p=="Nic"是一个where子句,select p是一个select子句,三个子句构成了一个LINQ表达式,一个LINQ表达式返回一个变量赋值给query。我们称query是一个查询,或者说query指定了一个LINQ查询。


LINQ的基本语法规范
预定义关键字:from,where,orderby,join,let,descending和select,group等。
表达式构成:必须以from子句开头,以select子句或者group子句结尾,在这两个子句中间,可以使用where,orderby,join,let,from子句。

如果你掌握了SQL,那么LINQ入门将会很容易。

使用上还需要注意的一些知识点:

  1. 一个LINQ表达式只是定义了一个查询,并未执行具体的查询。
  2. 具体的查询,需要foreach访问query时才会执行。
  3. 书写LINQ查询时有两种语法可供选择:方法语法(Fluent Syntax)和查询语法(Query Expression)。

1-1.条件查询和分组查询

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Product
    {
        public string ProductName { get; set; }
        public string Category { get; set; }
        public int Number { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //定义一个集合,集合和数组都实现接口IEnumerable,因此linq语句可以作用在集合和数组
            IList<int> list = new List<int>() { 2, 5, 7, 8, 10 };
            var result = from l in list
                         let a = l * 2
                         where a > 10
                         select a;
            //let 如果查询之前需要对集合中的元素进行运算,就写在let后面,计算结果要使用一个变量存放
            foreach(var item in result)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("=================================");
            IEnumerable<Product> list1 = new List<Product>(){
                new Product { ProductName = "李宁", Category = "鞋子",Number =100},
                new Product { ProductName="耐克", Category="鞋子", Number = 1100 } ,
                new Product { ProductName = "猫哆哩", Category = "食品", Number = 1300 },
                new Product { ProductName = "可乐", Category = "饮料", Number = 21010 },
                new Product { ProductName = "王老吉", Category = "饮料", Number = 2100 },
                new Product { ProductName = "子弟土豆片", Category = "食品", Number = 1200 },
                new Product { ProductName = "鲜橙多", Category = "饮料", Number = 4100 },
                new Product { ProductName = "农夫山泉", Category = "饮料", Number = 5100 }};
            //一个Linq表达式只是定义了一个查询,但是并未执行
            //执行时间:当时通过foreach或者for循环执行Linq时才真正执行了linq表达式
            //查询类别是饮料的产品信息
            //p代表的是list1里面的每个元素,p代表的就是每一个product对象
            var result1 = from p in list1
                          where p.Category == "饮料"
                          select p;
            foreach (var item in result1)
            {
                Console.WriteLine("饮料产品:{0},数量:{1}" ,item.ProductName,item.Number);
            }
            Console.WriteLine("=================================");
            //查询饮料产品且数量在5000以上的产品信息
            //分组group以主体进行分组by分组的关键字
            var result2 = from p in list1
                          group p by p.Category;

            foreach(var item in result2)
            {
                Console.WriteLine("产品类别:{0},总分组数为:{1}", item.Key, item.Count());
                foreach (var it in item)
                {
                    Console.WriteLine("产品名称:{0},产品数量:{1}", it.ProductName, it.Number);
                }
            }
        }
    }

}

运行结果:
在这里插入图片描述

1-2.into关键字的使用,以及自定义查询结果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Product
    {
        public string ProductName { get; set; }
        public string Category { get; set; }
        public int Number { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Product> list1 = new List<Product>(){
                new Product { ProductName = "李宁", Category = "鞋子",Number =100},
                new Product { ProductName="耐克", Category="鞋子", Number = 1100 } ,
                new Product { ProductName = "猫哆哩", Category = "食品", Number = 1300 },
                new Product { ProductName = "可乐", Category = "饮料", Number = 21010 },
                new Product { ProductName = "王老吉", Category = "饮料", Number = 2100 },
                new Product { ProductName = "子弟土豆片", Category = "食品", Number = 1200 },
                new Product { ProductName = "鲜橙多", Category = "饮料", Number = 4100 },
                new Product { ProductName = "农夫山泉", Category = "饮料", Number = 5100 }};
            //查询各个分类的名称及数量,只希望得到两列数据(分类名称和数量)
            var result3 = from p in list1
                          group p by p.Category into temp
                          select new { Title=temp.Key,Num=temp.Count()};
            foreach (var item in result3)
            {
                Console.WriteLine("产品类别:{0},总分组数为:{1}", item.Title, item.Num);
            }
        }
    }

}

运行结果:
在这里插入图片描述

1-3.对查询结果排序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Product
    {
        public string ProductName { get; set; }
        public string Category { get; set; }
        public int Number { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Product> list1 = new List<Product>(){
                new Product { ProductName = "李宁", Category = "鞋子",Number =100},
                new Product { ProductName="耐克", Category="鞋子", Number = 1100 } ,
                new Product { ProductName = "猫哆哩", Category = "食品", Number = 1300 },
                new Product { ProductName = "可乐", Category = "饮料", Number = 21010 },
                new Product { ProductName = "王老吉", Category = "饮料", Number = 2100 },
                new Product { ProductName = "子弟土豆片", Category = "食品", Number = 1200 },
                new Product { ProductName = "鲜橙多", Category = "饮料", Number = 4100 },
                new Product { ProductName = "农夫山泉", Category = "饮料", Number = 5100 }};
            //排序 order by 排序的关键词,默认升序,加入descending关键字则降序
            var result4 = from p in list1
                          orderby p.Number descending
                          select p;
            foreach (var item in result4)
            {
                Console.WriteLine("产品名称:{0},产品数量:{1}", item.ProductName, item.Number);
            }
        }
    }
}

运行结果:
在这里插入图片描述

注意:排序中默认是升序,关键字ascending可以不写,若要降序则需要写上descending。

2.方法语法的链接查询

示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "Tom","Dick","Harry","Marry","Jay"};
            IEnumerable<string> query = names.Where(n => n.Contains("a")).
                OrderBy(n => n.Length).
                Select(n => n.ToUpper());
            foreach (var item in query)
            {
                Console.WriteLine(item);
            }
        }
    }
}

运行结果:
在这里插入图片描述

上面代码的功能就是将数组中含有字符a的元素查询出来并转换成大写字母。

将之前的示例代码通过方法语法的方式进行修改

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Product
    {
        public string ProductName { get; set; }
        public string Category { get; set; }
        public int Number { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Product> list1 = new List<Product>(){
                new Product { ProductName = "李宁", Category = "鞋子",Number =100},
                new Product { ProductName="耐克", Category="鞋子", Number = 1100 } ,
                new Product { ProductName = "猫哆哩", Category = "食品", Number = 1300 },
                new Product { ProductName = "可乐", Category = "饮料", Number = 21010 },
                new Product { ProductName = "王老吉", Category = "饮料", Number = 2100 },
                new Product { ProductName = "子弟土豆片", Category = "食品", Number = 1200 },
                new Product { ProductName = "鲜橙多", Category = "饮料", Number = 4100 },
                new Product { ProductName = "农夫山泉", Category = "饮料", Number = 5100 }};
            //一个Linq表达式只是定义了一个查询,但是并未执行
            //执行时间:当时通过foreach或者for循环执行Linq时才真正执行了linq表达式
            //查询类别是饮料的产品信息
            //p代表的是list1里面的每个元素,p代表的就是每一个product对象
            var result1 = list1.Where(p=>p.Category=="饮料");
            foreach (var item in result1)
            {
                Console.WriteLine("饮料产品:{0},数量:{1}", item.ProductName, item.Number);
            }
            Console.WriteLine("=================================");
            //查询饮料产品且数量在5000以上的产品信息
            //分组group以主体进行分组by分组的关键字
            var result2 = list1.GroupBy(p=>p.Category);

            foreach (var item in result2)
            {
                Console.WriteLine("产品类别:{0},总分组数为:{1}", item.Key, item.Count());
                foreach (var it in item)
                {
                    Console.WriteLine("产品名称:{0},产品数量:{1}", it.ProductName, it.Number);
                }
            }
            Console.WriteLine("=================================");
            //查询各个分类的名称及数量,只希望得到两列数据(分类名称和数量)
            var result3 = list1.GroupBy(p => p.Category).
                Select(p => new { Title = p.Key, Num = p.Count() });
                
            foreach (var item in result3)
            {
                Console.WriteLine("产品类别:{0},总分组数为:{1}", item.Title, item.Num);
            }
            Console.WriteLine("=================================");
            //排序 order by 排序的关键词,默认升序,加入descending关键字则降序
            var result4 = list1.OrderByDescending(p=>p.Number);
            foreach (var item in result4)
            {
                Console.WriteLine("产品名称:{0},产品数量:{1}", item.ProductName, item.Number);
            }
        }
    }
}

运行结果:
在这里插入图片描述

可以看到结果和linq表达式的结果一样,linq的方法语法查询其实更符合我们的编写习惯。

针对上面的几个方法做如下解释:

  1. 在VS中可以看到Where,OrderBy,Select这几个方法都是Linq对IEnumerable接口的扩展方法,由于数组和集合都实现了IEnumerable接口,所以数组和集合也是可以使用的。
  2. 扩展方法中放的是一个lambda表达式,也就是一个匿名函数,转到定义可以看到,这些扩展方法的参数其实是一个委托,所以才将匿名函数作为参数。
  3. 当链接的使用查询运算符时,一个运算符的输出Sequence会成为下一个运算符的输入Sequence,其结果形成了一个Sequence的传输链。

2-1.对方法Where实现的研究

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp4
{
    public class Product
    {
        public string ProductName { get; set; }
        public string Category { get; set; }
        public int Number { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Product> list1 = new List<Product>(){
                new Product { ProductName = "李宁", Category = "鞋子",Number =100},
                new Product { ProductName="耐克", Category="鞋子", Number = 1100 } ,
                new Product { ProductName = "猫哆哩", Category = "食品", Number = 1300 },
                new Product { ProductName = "可乐", Category = "饮料", Number = 21010 },
                new Product { ProductName = "王老吉", Category = "饮料", Number = 2100 },
                new Product { ProductName = "子弟土豆片", Category = "食品", Number = 1200 },
                new Product { ProductName = "鲜橙多", Category = "饮料", Number = 4100 },
                new Product { ProductName = "农夫山泉", Category = "饮料", Number = 5100 }};
            
            //使用我们自己写的where方法和select
            var result1 = list1.MyWhere(p => p.Category == "饮料").
                MySelect(p=>p);
            foreach (var item in result1)
            {
                Console.WriteLine("饮料产品:{0},数量:{1}", item.ProductName, item.Number);
            }
            Console.WriteLine("=================================");
            //使用系统的where方法和select
            var result2 = list1.Where(p => p.Category == "饮料").
                Select(p => p.ProductName);
            foreach (var item in result1)
            {
                Console.WriteLine("饮料产品:{0},数量:{1}", item.ProductName, item.Number);
            }
            Console.WriteLine("=================================");
            //使用系统的where方法和select
            var result3 = list1.Where(p => p.Category == "饮料").
                Select(p => p.ProductName);
            foreach (var item in result3)
            {
                Console.WriteLine("饮料产品:{0}", item);
            }
            Console.WriteLine("=================================");
            //使用自己的where方法和select
            var result4 = list1.MyWhere(p => p.Category == "饮料").
                MySelect(p => p.ProductName);
            foreach (var item in result4)
            {
                Console.WriteLine("饮料产品:{0}", item);
            }
        }
    }

    /// <summary>
    /// 静态类,做扩展方法用
    /// </summary>
    public static class ListEx
    {
        /// <summary>
        /// 自写Where方法的内部结构
        /// </summary>
        /// <param name="lis">扩展类型</param>
        /// <param name="func">系统自带的一个委托</param>
        /// <returns></returns>
        public static IEnumerable<Product> MyWhere(this IEnumerable<Product> lis, Func<Product, bool> func)
        {
            foreach (var item in lis)
            {
                //这里的func相当于下面的这个lambda表达式
                //p => p.Category == "饮料"
                //将满足条件的item对象返回到IEnumerable中
                if (func(item))
                {
                    yield return item;
                }
            }
        }
        /// <summary>
        /// 自写Selecct方法的内部结构
        /// </summary>
        /// <param name="lis">扩展类型</param>
        /// <param name="func">系统自带的一个委托</param>
        /// <returns></returns>
        public static IEnumerable<Product> MySelect(this IEnumerable<Product> lis, Func<Product, Product> func)
        {
            foreach (var item in lis)
            {
                //这里的func相当于下面的这个lambda表达式
                //p => p
                //将item对象返回到IEnumerable中
                yield return func(item);
            }
        }
        /// <summary>
        /// 自写Selecct方法,这是一个重载,只返回一个属性
        /// </summary>
        /// <param name="lis">扩展类型</param>
        /// <param name="func">系统自带的一个委托</param>
        /// <returns></returns>
        public static IEnumerable<string> MySelect(this IEnumerable<Product> lis, Func<Product, string> func)
        {
            foreach (var item in lis)
            {
                //这里的func相当于下面的这个lambda表达式
                //p => p.ProductName
                //将item对象返回到IEnumerable中
                yield return func(item);
            }
        }
    }
}

运行结果:
在这里插入图片描述

分析:
两次运行结果一致,通过手写Where方法和Select方法,能更好的理解中间放lambda表达式的原因,以及实现过程。

2-2使用方法语法做查询练习

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp5
{
    public class Student
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
        public IEnumerable<int> Scores { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Student> list = new List<Student>()
            {
                new Student { Name ="张三",Sex ="男",Age=23,Scores =new List<int>() { 98,76,89,54}},
                new Student { Name ="李四", Sex ="男" ,Age=33,Scores =new List<int>(){ 89,76,89,45 } },
                new Student { Name ="王五" ,Sex ="男" ,Age=43,Scores =new List<int>() {98, 76, 89, 55} },
                new Student { Name ="刘一",Sex ="男",Age=23,Scores =new List<int>(){ 67,76,89,33} },
                new Student { Name = "夏天", Sex = "女", Age = 13, Scores = new List<int>() { 89, 76, 89, 56 } },
                new Student { Name = "薇薇", Sex = "女", Age = 23, Scores = new List<int>(){ 47, 76, 89, 67 } },
                new Student { Name = "肖小", Sex = "女", Age = 13, Scores = new List<int>() { 36, 76, 89, 48 } },
                new Student { Name = "武大", Sex = "男", Age = 63, Scores = new List<int>(){ 89, 76, 89, 69 } } };
            //统计班级男女生的人数,并保存到集合=》ListResult中
            var result = list.GroupBy(s => s.Sex).
                Select(s => new { Sex = s.Key, Num = s.Count() });
            //下面是等价的表达式语法查询
            //from a in list
            //group a by a.Sex into temp
            //select new { Sex = temp.Key, Num = temp.Count() };
            foreach (var item in result)
            {
                Console.WriteLine("性别:{0},人数:{1}", item.Sex, item.Num);
            }
            Console.WriteLine("==================================");
            //计算男生同学的总分和平均分
            var result1 = list.Where(s => s.Sex == "男").
                Select(s => new { Name = s.Name, Sum = s.Scores.Sum(), Avg = s.Scores.Average() });
            foreach (var item in result1)
            {
                Console.WriteLine("姓名:{0},总分:{1},平均分:{2}", item.Name, item.Sum,item.Avg);
            }
            Console.WriteLine("==================================");
            //计算男生,年纪30以上的同学的最高分和最低分,并对计算的最高分进行降序排序
            var result2 = list.Where(s => s.Sex == "男" && s.Age > 30).
                OrderByDescending(s=>s.Scores.Max()).
                Select(s => new { Name = s.Name,Age=s.Age, Max = s.Scores.Max(), Min = s.Scores.Min() });
            foreach (var item in result2)
            {
                Console.WriteLine("姓名:{0},年龄:{1},最高分:{2},最低分:{3}", item.Name,item.Age, item.Max, item.Min);
            }
        }
    }
}

运行结果:
在这里插入图片描述

上述代码可以自行修改为使用linq表达式的结构来进行查询,方法同理。

2-3元素操作

方法名说明
ElementAt返回集合中指定索引处的元素
ElementAtOrDefault返回集合中指定索引处的元素,如果索引超出范围则返回默认值
First返回集合中的第一个元素或满足条件的第一个元素
FirstOrDefault返回集合中的第一个元素或满足条件的第一个元素,如果没有则返回默认值
Last返回集合中的最后一个元素或满足条件的最后一个元素
LastOrDefault返回集合中的最后一个元素或满足条件的最后一个元素,如果没有则返回默认值
Single返回集合中的唯一元素或满足条件的唯一元素
SingleOrDefault返回集合中的唯一元素或满足条件的唯一元素,如果没有,则返回默认值

2-4数据类型转换操作的使用

方法名说明
ToList将集合转换为List
ToArray将集合转换为数组
ToDictionary根据键选择器函数将元索放入Dictionary<TKey,Tvalue>中
ToLookup根据键选择器函数将元索放入Lookup<Tkey,Telement>中
AsEnumerable将一个序列转换为IEnumerable集合
AsQueryable将lEnumerable转换为IQueryable
Cast将集合的元素强制转换为指定类型
OfType根据值强制转换为指定类型的能力筛选值

3LINQ总结

LINQ主要关键字: from、where、select、group、orderby。
方法语法的本质是通过扩展方法和Lambda表达式来创建查询。
聚合操作的主要方法:Count、Max、Min、Sum、Average。
数据类型转换操作的主要方法:ToList、ToArray、AsEnumerable、Cast、OfType。

八、EF的基本使用

1.什么是ORM

ORM全称是“对象关系映射”(Object-Relation Mapping)。
ORM是将关系数据库中的数据用对象的形式表现出来,并通过面向对象的方式将对象组织起来,实现系统业务逻辑的过程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值