C#中的Linq查询(条件封装)

最开始的对象查询是用foreach来遍历输出
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把数据全部拿出来在去内存里做筛选。

 

posted @ 2022-10-29 02:56  Akai_啊凯  阅读(1927)  评论(0编辑  收藏  举报