Entity Framework Core 2.X Crash Tutorial (4)


这一小节的主要的内容是继续了解EFCore的执行过程,包括查询过滤和删除等操作。

EFCore查询过滤

一般地,查询过滤我们会这么写:

var provinces = context.Provinces
   .Where(x=>x.Name=="北京");

这种Lamda表达式,相当于是:没有名称的一个方法(匿名方法)接受一个参数,即province对象。如果要替换Landa表达式,可以这么写:

 public IActionResult Index()
 {
   var provinces = context.Provinces
     .Where(FilterBeijing);
   foreach (var province in provinces)
   {
    //Add action
   }
   return View();
 }

 private bool FilterBeijing(Province p)
 {
   return p.Name == "北京";
 }

查询参数时,参数的设置:
1)当写死参数的时候,在执行SQL语句的时候,参数也是固定的。即Where(x=>x.Name=="北京")对应了Select * from xxx where x.Name='Beijing'

public IActionResult Index()
 {
   var provinces = context.Provinces
     .Where(x=>x.Name=="北京");
   foreach (var province in provinces)
   {
     Console.WriteLine(province.Name);
     //...
   }
   return View();
 }

这样其实是有风险的,因为EFCore会认为这个参数是安全的,会原封不动的把这个参数写在SQL语句里面。
ParamsFixed
2)参数提出来,放到变量里来,然后把变量放到Linq,查看SQL语句。即
var param ="北京";xxx.Where(x=>x.Name== param);
Parameters=@_param_0='Beijing'
…Where [x].[Name]=@_param_0
EFCore同样也会使用带参数的SQL语句,这样避免了很多风险。

 public IActionResult Index()
 {
   var param = "北京";
   var provinces = context.Provinces
   .Where(x=>x.Name== param);
   foreach (var province in provinces)
   {
     Console.WriteLine(province.Name);
     //...
   }
   return View();
 }

ParamsNotFixed
会立即执行查询的Linq方法:

  • ToList() 返回一个集合
  • First() 必须至少有一笔数据,返回第一笔,单笔数据。如果没有数据,则会抛异常。
  • FirstOrDefault() 按照查询条件,如果有就返回第一笔;没有就返回Null,不会抛异常。
  • Single() 期待我们过滤完查询之后,结果只有一笔数据。如果有多余一笔数据,或者没有数据,都会抛出异常。
  • SingleOrDefault() 如果查询的结果没有一条复查查询结果,那么久返回Null;如果有一笔就返回一笔,如果有两笔的话也会抛出异常。
  • Last()
  • LastorDefault()
  • Count()
  • LongCount()
  • Min()
  • Max()
  • Average()

会立即执行查询的非Linq方法:

  • Find(主键)

FirstorDefault有两种写法,但是更推荐第二种紧凑一点的写法。

 public IActionResult Index()
 {
   var param = "北京";
   //Method 1
   var province1 = context.Provinces
     .Where(x => x.Name == param)
     .FirstOrDefault();
   //Method 2
   var province2 = context.Provinces
     .FirstOrDefault(x => x.Name == param);
   return View();
 }

FirstorDefault
根据主键来查询的两种方法如下。使用Find方法是DbSet的方法,如果这个对象已经在内存里被追踪了,那么这时候就不会去查找数据库,直接返回内存中的这个对象。

 public IActionResult Index()
 {
   var param = "北京";
   var province1 = context.Provinces
     .FirstOrDefault(x => x.Id == 3);
   var province2 = context.Provinces.Find(3);
   return View();
 }

过滤查询时会用到模糊查询,以前也许是这么写过滤条件:

 public IActionResult Index()
 {
   var param = "北京";
   var province1 = context.Provinces
     .Where(x => x.Name.Contains("北"));
   return View();
 }

LikeQuery
上面这个操作相当于模糊查询 Name like "%b北京%"
EFCore中有个新的方法:

 public IActionResult Index()
 {
   var province1 = context.Provinces
     .Where(x => EF.Functions.Like(x.Name, "%北%"))
     .ToList();
   return View();
 }

EFFunctionLike
当然这里还是推荐使用参数的方法来写:

 public IActionResult Index()
 {
   string param = "%北%";
   var province1 = context.Provincedds
     .Where(x => EF.Functions.Like(x.Name, param))
     .ToList();
   return View();
 }

下面看一下LastOrDefault,使用LastOrDefault首先要用Order排序;如果不排序的话就会使用内存中的顺序,这样结果是未知的。

 public IActionResult Index()
 {
   string pa = "%北%";
   var province1 = context.Provinces
     .OrderBy(x=>x.Id)
     .LastOrDefault(x => EF.Functions.Like(x.Name, pa));
   return View();
 }

LastOrDefault

EFCore修改数据

 public IActionResult Index()
 {
   string pa = "%北%";
   var province = context.Provinces.FirstOrDefault();
   if (province!=null)
   {
     province.Population += 100;
     context.SaveChanges();
   }
   return View();
 }

这里面有两笔操作,首先查出来,然后根据Id去Update。这种情况下,context一直追踪着province这个对象。
EFCoreUpdate
当然,EFCore是支持批量修改的,举个例子:当context中有一个修改一个新增:

 public IActionResult Index()
 {
   string pa = "%北%";
   var province = context.Provinces.FirstOrDefault();
   if (province!=null)
   {
     province.Population += 100;
     context.Provinces.Add(new Province
   {
     Name = "江苏",
     Population = 90000000
   });
     context.SaveChanges();
   }
   return View();
 }

EFCoreMultipleUpdate

EFCore离线修改

首先要修改一下MyContext的生命周期。原本默认是scope,scope的生命周期是每次http请求生成一个实例。
现在要修改成Transient,Transient 是每次有需要的时候都可以创建一个MyContext实例
startup.cs中修改:

public void ConfigureServices(IServiceCollection services)
 {
   services.Configure(options =>
   {
     // This lambda determines whether user consent for non-essential cookies is needed for a given request.
     options.CheckConsentNeeded = context => true;
     options.MinimumSameSitePolicy = SameSiteMode.None;
   });
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
   services.AddDbContext( options =>
   {
     options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), opts =>
     {
       opts.MaxBatchSize(20000);
     });
     options.EnableSensitiveDataLogging(true);
   },ServiceLifetime.Transient);
 }

在Controller中,添加另一个DbContext2,进行操作(context和context2不是同一个对象):

 public class HomeController : Controller
 {
   private readonly MyContext context;
   private readonly MyContext context2;
   public HomeController(MyContext context,MyContext context2)
   {
     this.context = context;
     this.context2 = context2;
   }
   public IActionResult Index()
   {
     var province = context.Provinces.FirstOrDefault();
     context2.Provinces.Update(province);
     context2.SaveChanges();
     return View();
   }
}

离线修改 相当于告诉context2我的province对象需要修改,除了Id其他都要改。 当然Update()也有UpdateRange()批量修改方法。
OfflineEFCoreUpdate

EFCore删除

EFCore删除 ,只能删除追踪的对象,即已经查出来的对象。
当然删除也是支持离线的,支持批量删除的,即有RemoveRange()方法。

 public IActionResult Index()
 {
   var province = context.Provinces.FirstOrDefault();
   context2.Provinces.Remove(province);
   context2.SaveChanges();
   return View();
 }

EFCoreDelete

原始SQl特性的支持

执行命令:DbContext.Database.ExecuteSqlCommand()
查询命令:DbSDet.FromSql()
根据Id执行存储过程

 public IActionResult Index()
 {
   var id=5;
   context.Database.ExecuteSqlCommand("exec Del……");
   return View();
 }

文章作者: Chaoqiang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Chaoqiang !
评论
 上一篇
Entity Framework Core 2.X  Crash Tutorial (5) Entity Framework Core 2.X Crash Tutorial (5)
这一小节的内容主要是EFCore对关联数据的查询和修改。 EFCore 保存关联数据首先看下保存关联数据,以Province和City举例,这是一个一对多的关系。实例一: public IActionResult Index() {
下一篇 
Entity Framework Core 2.X  Crash Tutorial (3) Entity Framework Core 2.X Crash Tutorial (3)
这一小节主要的内容是通过观察EFCore的执行日志了解EFCore的执行过程。 将EFCore的SQL执行过程输出到Log输出到Console:ASPNetCore的项目已经集成好了Log工具,可以通过查看Program.cs中的Creat
  目录