没有logger,EF的内部运行就是一个“黑箱”:
EF core需要在OnConfiguring()中配置:
optionsBuilder .UseSqlServer(connString) .EnableSensitiveDataLogging() //这样log中就包含了数据库数据
为了能够获得最详细(包含在数据库中)的信息,我们需要“开启敏感数据日志”:EnableSensitiveDataLogging()。但是,项目发布以后,这样做就会有安全风险(黑客有可能拿到log文件)。怎么办呢?使用条件编译符:
#if DEBUG //仅在调试状态使用 .EnableSensitiveDataLogging(true) #endif
然后继续配置
.LogTo( (id, level) => level == LogLevel.Error, //过滤条件 log => Console.WriteLine(log) //如何记录log );类似于log4net,EF中为Log设定了不同的Level (F12演示),通常:
设断点演示:debug时输出显示log信息
PS:ASP.NET core中自动集成logger,详见:ASP.NET Core documentation.
我们首先学习单个entity的数据库操作。
数据的增删改查一样依赖两个EF核心对象:
EF的DbContext和DbSet都提供了基于Unit Of Work and Repository patterns(F12演示DbContext注释)的增删改查方法:
我们首先实例化一个DbContext:
SqlDbContext context = new SqlDbContext();
首先需要一个entity对象:
Student student = new Student { //Id = 1000, Name = "李智博" };然后,将其添加到DbContext或DbSet中:
context.Students.Add(student);最后,将改动同步到数据库:
context.SaveChanges();
关键在于:
Find()方法可以(也只能是)通过主键(可以是联合主键)查找到对应的Entity。
Student student = context.Students.Find(1);
演示:略
通常来说,我们会首先通过DbContext得到一个entity,
Student student = repository.Find<Student>(6);
然后再通过Remove()将其删除:
context.Students.Remove(student); //或者:
最后进行同步。
注意:一定要是通过context.Find()出来的entity才行!
这样更符合逻辑:删除的是从DbContext中获取的那个Id=6的Student……
本质上,EF并没有专门的“改”的方法。惯常的办法是从DbContext中获取到entity后予以修改,
Student student = context.Find<Student>(1003); student.IsFemale = true;
然后SaveChanges()予以同步。
注意:EF会检查entity有无“实质性的”更改,仅当entity属性真正的更改之后,EF才会生成UPDATE语句进行更新。
在EFcore里,所有DbSet引导的方法,也都可以由DbContext点出:
context.Add<Student>(student);
甚至还可以省略泛型参数:
context.Add(student);其他:
context.Remove<Student>(student);
context.Remove(student);
Student student = context.Find<Student>(1);//但这里的泛型参数不能省略
还可以使用AddRange()和RemoveRange()添加/删除多个entities。
并不是每次增删改都需要调用,可以在所有entity操作完成之后,调用一次之后,就能一次性的将所有entity改动同步到数据库。
而且DbContext是跨entity的!演示:
Student atai = context.Students.Find(2); atai.Name = "--阿泰--"; atai.Age = 19; Student ljp = context.Find<Student>(3); context.Students.Remove(ljp); Teacher fg = new Teacher { Name = "飞哥" }; context.Add(fg); context.SaveChanges();
如果不是因为疏忽,就是因为没有理解到:
EF依靠DbContext来管理/维护/追踪entity,如果一个entity:
复习:会话/状态管理
EF的DbContext中维护着一个ChangeTracker:追踪记录着所有需要被“同步”到数据库的entity的“改动”。
断点调试演示:
用watch查看 DbContext.ChangeTracker.DebugView:
当一个new Student()被Add()到context,其LongView内容为:
Student {Id: -2147482647} Added Id: -2147482647 PK Temporary IsFemale: 'False' Name: '李智博'
其中 Added,表明了该entity此时的状态(EntityState)。
此外,(演示)
当调用SaveChanges()时,EF会根据ChangeTracker的内容,决定相应的生成相应的Insert/Delete语句。
断点演示:改变entity的属性值不会改变其状态。
@想一想@:为什么?
EF还没这个本事监控entity的属性值更改,^_^
PS:EF也是C#写的,C#做不到的事,EF也没办法。
EF只能在SaveChanges()的时候,将
进行比对(detect),如果:
UPDATE [Students] SET [Age] = @p0 WHERE [Id] = @p1;注意:仅更改了Age列,因为只有Age发生改变!
EF里面暂时没有根据Id生成proxy entity( LazyLoad)的语法。这样删改就会先有一个SELECT的过程,必须先Find()或Where()。
但我们可以用“变通”的方式,直接new一个只有Id的entity,代替Find()或Where()之后的结果:
Bed bed = new Bed{ Id = 1};然后,
context.Set<Bed>().Remove(bed);
这样就不会有SELECT的过程,能够在context.SaveChanges()时生成DELETE语句删除这个Bed。
要麻烦一点,需要首先将bed对象纳入context的追踪:
context.Set<Bed>().Attach(bed); bed.Size = 12;
除了Add()以外,还有这两个方法,可以把context之外的entity纳入context追踪管理。
他们的区别在于:
而当entity有主键值时:
UPDATE [Students] SET [Age] = @p0, [Enroll] = @p1, [IsFemale] = @p2, [Name] = @p3 WHERE [Id] = @p4;
Student s7 = new Student { Id = 7 }; repository.Attach<Student>(s7); s7.Age = 23;//注意先后顺序! repository.SaveChanges();
UPDATE [Students] SET [Age] = @p0 WHERE [Id] = @p1;
@想一想@:直接Update时使用Update()行不行?为什么?
复习:定义和作用
Student lzb = context.Find<Student>(1); lzb.Name = "李智博"; Teacher fg = context.Find<Teacher>(1); fg.Salary = -100; //违反自定义CHECK必须≥0 context.SaveChanges();
注意:
using (IDbContextTransaction transaction = context.Database.BeginTransaction()) { try { Student lzb = context.Find<Student>(1); lzb.Name = "lzb"; context.SaveChanges(); Teacher fg = context.Find<Teacher>(1); fg.Salary = -100; //负数不行,必须0或正数 context.SaveChanges(); transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } }
断点演示:事务提交/回滚
注意:transaction对象不是来源于DbContext,而是context.Database,所以可以形成“跨context”事务
@想一想@:如果在catch中注释掉transaction.Rollback();,会是什么结果?
即TransactionScope,在.NET core 2.1之后被支持,写法同ADO.NET。
ORM概述第4题
多快好省!前端后端,线上线下,名师精讲
更多了解 加: