C#中的Linq查询(条件封装)
List<string> fruits = new List<string>() { "苹果", "香蕉", "西瓜", "香瓜" };//{}对象集合初始化器,没有构造函数的初始化 Console.Write("请输入水果名:"); string str = Console.ReadLine(); foreach (var itme in fruits) { if (itme.Contains(str)) Console.WriteLine(itme);//Contains模糊查询条件 }
Linq查询原理:其实就是把查询条件进行封装成一些个扩展方法
Linq to object(数组跟集合)查询的是内存数据
Linq to sql (数据库)查询数据库数据
Linq to XML 查询xml文件用的
其实他们条件语法都一样,只是查询对象不同。
这里添加实体类做数据演示:linq to obj 做内存集合数据源
//给实体类存放一些初始值 List<Students> plist = new List<Students>() { new Students() { Id = 1, Name = "a冰箱", Price = 2300, Brand = "西门子1", Sell = "B202",lover = new List<string>(){ "苹果", "香蕉", "西瓜" }}, new Students() { Id = 2, Name = "b冰箱", Price = 2400, Brand = "西门子2", Sell = "B303",lover = new List<string>(){ "木瓜", "芒果", "地瓜" }}, new Students() { Id = 3, Name = "c电视", Price = 2500, Brand = "西门子3", Sell = "B404",lover = new List<string>(){ "橘子", "柿子", "水果" }}, new Students() { Id = 4, Name = "d电视", Price = 2600, Brand = "西门子4", Sell = "B505",lover = new List<string>(){ "柚子", "香瓜", "西瓜" }} }; void Show(List<Students> fruits) { foreach (var itme in fruits) { Console.WriteLine("编号:{0},商品名称:{1},商品价格:{2},商品品牌:{3},商品型号:{4}", itme.Id, itme.Name, itme.Price, itme.Brand, itme.Sell); } } Show(plist); /// <summary> /// 实体类Model:作用于数据传递。 /// </summary> public class Students { public Nullable<int> Id { get; set; } //Nullable<int>表示值类型也可以赋空值 int? id = null 就不会不错 一般来说int是没有空值 string有 public string Name { get; set; } public int? Price { get; set; } // int? 是 Nullable<int> 的简化 ,用于值类型,表示可以为空null public string Brand { get; set; } public string Sell { get; set; } public List<string> lover { get; set; } }
自定义linq:if语句的条件判断一步步演变过来的
var list = plist.MyWhere(x => x.Id == 1 && x.Name == "a冰箱").ToList();//自定义linq查询条件的筛选方法 Show(list); public static class LinqExtend //扩展方法只能定义在静态类中,给IEnumerable接口添加MyWhere方法,IEnumerable是可迭代枚举型,可以被foreach遍历 { public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> ts, Func<T, bool> func) //委托返回布尔值,Invoke执行委托,写不写都可以:func(item)也可以执行。 { List<T> list = new List<T>(); foreach (var item in ts) { if (func.Invoke(item)) list.Add(item); } return list; } }
系统linq:上面是Where方法内部大概语法。where是官方给的扩展方法。
var list = plist.Where(x => x.Id == 1 && x.Name == "a冰箱").ToList();//系统linq的扩展方法where查询条件 Show(list);
Linq语法官方给了两种写法:IEnumerable<T>接口的【扩展方法式】和【表达式】
linq表达式:这种方式最后生成代码和扩展方法式是一样的,最后代码翻译为方法式。所以建议使用扩展方法式。表达式语法:Select * from 数据源(表明)
var list = (from f in plist //数据源:也就是一个集合,遍历list orderby f.Id descending //orderby排序(默认的升序) 跟 descending降序 (ascending升序) where f.Name.Contains("冰箱") //Contains模糊查询 select f).ToList();//显示结果返回给reus变量,可查询字段(如果查询全部直接放变量名) 就像f是变量名 数据库字段 f.id 这种得到字段的所有值 Show(list);
select方法是投影,
var list = plist.Select(s => new { id = s.Id, name = s.Name }).ToList();//var s = new {} 匿名类,匿名对象。 foreach (var itme in list) Console.WriteLine(itme.id + ":" + itme.name);
from复合子句:多集合查询,查询条件是一个集合,数据源也是一个集合
string lovers = "苹果,香瓜"; List<string> loverlist = lovers.Split(',').ToList();//根据用户输入爱好 ,号来划分字符串 var list = from f in plist//数据源也是一个集合:使用复合子句把数据源集合变成一个一个的字符串 from loveritem in f.lover where loverlist.Contains(loveritem) //查询条件是一个集合 select f; Show(list.ToList());//显示数据的方法
复合子句Select查询单个字段
string lovers = "苹果,香瓜"; List<string> loverlist = lovers.Split(',').ToList();//根据用户输入 ,号来划分字符串 var list = from f in plist//数据源 from loveritem in f.lover where loverlist.Contains(loveritem) select f.Name; //复合字句查询,单个字段不是全部字段 List<string> unamelist = list.ToList(); foreach (var item in unamelist) { Console.WriteLine(item); }
复合子句Select查询多个字段
string lovers = "苹果,香瓜"; List<string> loverlist = lovers.Split(',').ToList();//根据用户输入 ,号来划分字符串 var list = from f in plist//数据源 from loveritem in f.lover where loverlist.Contains(loveritem) select new { //复合子句查询,多字段 a = f.Id, b = f.Name, c = f.Price }; foreach (var item in list) { Console.WriteLine("编号:{0},产品名:{1},价格:{2}", item.a, item.b, item.c); }
join多表连接查询:建议使用表达式
var table2 = new[] { new { id = 1, name = "张三" }, new { id = 2, name = "李四" } };//定义第二张表,初始化两条数据 var list = from p in plist //连几个表就加几个join往后写即可 join t in table2 on p.Id equals t.id //需要用equals表示等于,这里不能向数据库语法一样用==号。 select new { aa = p.Id, bb = p.Name, cc = t.name };//select在数据库里就是查询对象的一个临时表集合。 foreach (var itme in list) { Console.WriteLine($"编号:{itme.aa},名称:{itme.bb},姓名:{itme.cc}"); }
join多表查询的扩展方法式,如果是3张表以上就不方便
var table2 = new[] { new { id = 1, name = "张三" }, new { id = 2, name = "李四" } };//定义第二张表,初始化两条数据 var list = plist.Join(table2, p => p.Id, t => t.id,//参数1:连接的表,参数2:委托返回表1id,参数2:委托返回表2id,相当于连接条件:p.id ==t.id (p, t) => new { aa = p.Id, bb = p.Name, cc = t.name });//参数3:相当于select,委托两个参数返回一个临时表集合 foreach (var itme in list) { Console.WriteLine($"编号:{itme.aa},名称:{itme.bb},姓名:{itme.cc}"); }
linq查询的其他扩展方法
var list = plist.Skip(5)//跳过5条数据,分页会用到 .Take(3)//显示前面3条数据,.Concat(plist.Take(5));可以返回行数,查询到的数据条数 .OrderByDescending(x => x.Id) //降序,OrderBy是升序 .Where(s => s.Name.Contains("冰箱"))//Contains包含,模糊查询用,FirstOrDefault也一样放where条件类名才能加参数。 .FirstOrDefault();//返回第一个查询到的,没有就返回null,而First查不到就报错,这个不是模糊查询,数据要一致匹配。
linq to sql:数据库查询 IQueryable接口的AsQueryable方法
连接测试数据库:这里通过ADO.net创建实体数据模型的一个上下文映射类。ADO连接方式已经被淘汰不用研究,这里只是用来了解linq to sql语法
create database OA go use OA go create table userinfo ( id int primary key identity(1,1), name nvarchar(20), sex char(5), age int, ) insert into userinfo values('张三','男',19) insert into userinfo values('麻花','女',17) insert into userinfo values('小二','男',20) select * from userinfo
OAEntities OA = new OAEntities();//数据库对象,用ado.net实体数据模型创建出来的上下文映射对象。就当测试数据库用 //linq to sql 数据库查询 语法:数据库对象.表名.AsQueryable方法,主要查询数据库默认都是AsQueryable(),使用可以省略不写 var list = OA.userinfo.Where(s=>s.id>0).Where(s=>s.age>16).ToList(); foreach (var item in list)Console.WriteLine(item.id);//遍历输出显示
IQueryable接口其实也是继承了IEnumerable可迭代枚举型。只是IQueryable增加了一些功能,用于查询数据库。
IQueryable:是在数据库了处理好条件查询,在拿出来遍历。---AsQueryable() 方法:对象是数据库,默认的可以不写。
IEnumerable:则把数据全部拿出来到内存里做筛选,如果数据多这样就会很占用空间。---AsEnumerable() 方法:对象是内存中【类,字符串,数组等等】。默认的所以也没写出来。
如果加方法就变成转换,如:其实数据库也可以用AsEnumerable方法,因为他本来IQueryable就继承IEnumerable。只是IEnumerable只能筛选内存数据。所以就有了IQueryable。
OAEntities OA = new OAEntities(); //语法:数据库对象.表名.AsQueryable方法,主要查询数据库默认都是AsQueryable(),省略不写 var list = OA.userinfo.AsEnumerable().Where(s=>s.id>0).Where(s=>s.age>16).ToList();//改为AsEnumerable内存筛选查看区别。 foreach (var item in list)Console.WriteLine(item.id);//遍历输出显示
可以运行SQL跟踪工具查看这两个区别
很显然AsQueryable把条件都传到数据库了去执行筛选。而AsEnumerable把数据全部拿出来在去内存里做筛选。