Entity Framework Code First使用DbContext查询
DbContext、DbSet及DbQuery是Entity Framework Code First引入的3个新的类,其中DbContext用于保持数据库会话连接,实体变化跟踪及保存,DbSet用于暂存实体类的变化跟踪,DbQuery用于提供查询跟你。
1、使用Set查询全部记录
使用DbContext查询首先需要保证DbContext的实例在使用完之后对资源的释放,释放DbContext实例资源的方法有两种:采用using代码块结构和调用DbContext实例的Dispose()方法。
using (var ctx = new PortalContext()) { foreach (var province in ctx.Provinces) { Console.WriteLine(province.ProvinceName); } }
using (var ctx = new PortalContext()) { foreach (var province in ctx.Set<Province>()) { Console.WriteLine(province.ProvinceName); } }
2、使用LINQ排序、筛选等
1>、LINQ排序
LINQ表达式排序:
using (var ctx = new PortalContext()) { var provinces = from p in ctx.Provinces orderby p.ProvinceNo select p; foreach (var province in provinces) { Console.WriteLine(province.ProvinceName); } }
LINQ表达式多字段排序:
using (var ctx = new PortalContext()) { var provinces = from p in ctx.Provinces orderby p.ProvinceNo descending, p.ProvinceName ascending select p; foreach (var province in provinces) { Console.WriteLine(province.ProvinceName); } }
LINQ扩展方法排序:
using (var ctx = new PortalContext()) { var provinces = ctx.Provinces .OrderBy(p => p.ProvinceNo); foreach (var province in provinces) { Console.WriteLine(province.ProvinceName); } }
LINQ扩展方法多字段排序:
var provinces = ctx.Provinces .OrderByDescending(p => p.ProvinceNo) .ThenBy(p => p.ProvinceName); foreach (var province in provinces) { Console.WriteLine(province.ProvinceName); }
注:在采用LINQ扩展方法进行多字段排序时,多出现多个OrderBy,则只按最后一个OrderBy字段进行排序。
如下示例只会按照ProvinceName进行升序排序:
var provinces = ctx.Provinces .OrderByDescending(p => p.ProvinceNo) .OrderBy(p => p.ProvinceName);
2>、LINQ筛选
LINQ表达式筛选:
using (var ctx = new PortalContext()) { var cities = from c in ctx.Cities where c.ProvinceID == 3 select c; foreach (var city in cities) { Console.WriteLine(city.CityName); } }
LINQ表达式多字段筛选:
using (var ctx = new PortalContext()) { var cities = from c in ctx.Cities where c.ProvinceID == 3 && c.CityID > 10 select c; foreach (var city in cities) { Console.WriteLine(city.CityName); } }
LINQ表达式筛选与排序:
using (var ctx = new PortalContext()) { var cities = from c in ctx.Cities where c.ProvinceID == 3 && c.CityID > 10 orderby c.CityID select c; foreach (var city in cities) { Console.WriteLine(city.CityName); } }
LINQ扩展方法筛选:
using (var ctx = new PortalContext()) { var cities = ctx.Cities .Where(c => c.ProvinceID == 3); foreach (var city in cities) { Console.WriteLine(city.CityName); } }
LINQ扩展方法多字段筛选:
using (var ctx = new PortalContext()) { var cities = ctx.Cities .Where(c => c.ProvinceID == 3 && c.ProvinceID > 10); foreach (var city in cities) { Console.WriteLine(city.CityName); } }
LINQ扩展方法多字段筛选及排序:
var cities = ctx.Cities .Where(c => c.ProvinceID == 3 && c.ProvinceID > 10) .OrderBy(c=>c.CityID);
3>、LINQ选择读取字段
LINQ表达式读取1个字段:
var cities = from c in ctx.Cities where c.ProvinceID == 3 && c.CityID > 10 select c.CityName;
LINQ表达式读取多个字段:
var cities = from c in ctx.Cities where c.ProvinceID == 3 && c.CityID > 10 select new { c.CityID, c.CityName };
LINQ扩展方法读取1个字段:
using (var ctx = new PortalContext()) { var citieNames = ctx.Cities .Where(c => c.ProvinceID == 3 && c.ProvinceID > 10) .OrderBy(c => c.CityID) .Select(c => c.CityName); foreach (var cityName in citieNames) { Console.WriteLine(cityName); } }
LINQ扩展方法读取多个字段:
using (var ctx = new PortalContext()) { var cities = ctx.Cities .Where(c => c.ProvinceID == 3 && c.ProvinceID > 1) .OrderBy(c => c.CityID) .Select(c => new { c.CityID, c.CityName }); foreach (var c in cities) { Console.WriteLine("{0}-{1}", c.CityID, c.CityName); } }
3、查询本地数据
Entity Framework Code First通过DbSet的Local属性查询本地数据,查询本地数据的使用情况:1>当需要查询的数据已经存在与内存中,而不想再次发送SQL语句到数据库中取查询;2>当最新的数据还只在内存中而未提交到数据库的情况对内存数据进行查询。
示例:初始时本地未加载内存数据
using (var ctx = new PortalContext()) { var count = ctx.Cities.Local.Count; Console.WriteLine("Cities in memory:{0}", count); }
执行后返回的结果:
Cities in memory:0
示例:先通过查询,将数据加载到内存
using (var ctx = new PortalContext()) { foreach (var city in ctx.Cities) { Console.WriteLine(city.CityName); } var count = ctx.Cities.Local.Count; Console.WriteLine("Cities in memory:{0}", count); }
执行后返回的结果:
......
Cities in memory:342
3.2>、使用Load方法将数据加载到内存
using (var ctx = new PortalContext()) { ctx.Cities.Load(); var count = ctx.Cities.Local.Count; Console.WriteLine("Cities in memory:{0}", count); }
执行后的结果:
Cities in memory:342
using (var ctx = new PortalContext()) { var expr = from c in ctx.Cities select c; expr.Load(); var count = ctx.Cities.Local.Count; Console.WriteLine("Cities in memory:{0}", count); }
3.2>、基于本地数据进行查询
using (var ctx = new PortalContext()) { ctx.Cities.Load(); var cities = from c in ctx.Cities.Local orderby c.ProvinceID select c; foreach (var city in cities) { Console.WriteLine("{0}", city.CityName); } }
清除内存数据:
ctx.Cities.Local.Clear();
4、查询单个对象
DbContext API可以使用DbSet.Find来查询返回单个对象,DbSet.Find接受的参数值为需要查询的主键值,若未找到符合条件的主键值则返回null。
Find查找单个对象的规则:
1>、从内存中查找已经存在的从数据库中加载出来的实体或已经被附加到DbContext的实体;
2>、查找新添加的但还未被提交保存到数据库中的实体对象;
3>、到数据库中取查找还未加载到内存中的实体对象。
using (var ctx = new PortalContext()) { var city = ctx.Cities.Find(1); if (city != null) { Console.WriteLine(city.CityName); } else { Console.WriteLine("City not found!"); } }
若实体类具有多个主键,则Find方法同样接受全部主键的参数值,参数的顺序必须与主键列的顺序相同。
var city = ctx.Cities.Find(keyID, cityID);
Single方法也可以用于查询后返回单个对象:
using (var ctx = new PortalContext()) { var expr = from c in ctx.Cities where c.CityID == 1 select c; var city = expr.Single(); }
SingleOrDefault方法查询返回单个对象:
using (var ctx = new PortalContext()) { var expr = from c in ctx.Cities where c.CityID == 1 select c; var city = expr.SingleOrDefault(); if (city != null) { Console.WriteLine(city.CityName); } else { Console.WriteLine("City not found!"); } }
Single与SingleOrDefault方法的区别在于:当不存在满足条件的单个实体时,Single将直接抛出异常,而SingleOrDefault则返回class类型的默认值null。