EFCore_表达式树
什么是表达式树在之前的章节中,我们用委托的形式生成了SQL语句,但是这个生成SQL语句的过程是怎么进行的呢?在编译原理这门课中会讲到表达式树:将一个表达式比如b.Price>5,转为一个树,这棵树的根节点是大于号,左节点是成员访问符,右节点是5,根节点的左节点的左节点是b,根节点的左节点的右节点是Price,EFCore可以通过遍历这样的表达式树生成对应的SQL语句。
表达式树(Expression)和委托的不同我们用Expression<TDelegate>类型表示表达式树,具体代码如下:
123456789static void Main(string[] args) { Expression<Func<Article, bool>> e1 = a => a.Id > 5; //Expression<Func<Article,bool>> f2= a => { a.Id < 3};注意,这样的写法不被允许,因为在语句体写法中可能夹杂其他语句导致无法翻译 ...
EFCore_并发控制
并发控制概念避免多个用户同时操作资源造成的并发冲突问题。最好的解决方案:非数据库解决方案数据库层面的两种策略:悲观、乐观。
悲观并发控制1、悲观并发控制一般采用行锁、表锁等排他锁对资源进行锁定,确保同时只有一个使用者操作被锁定的资源。2、EF Core没有封装悲观并发控制的的使用,需要编写原生SQL语句来使用悲观并发控制。不同数据库的语法不一样。
方案1、实体类
12345class House{ public long Id {get;set;} public string Name {get;set;} public string Owner {get;set;}}
2、MySql方案:
1select * from T_Houses where Id=1 for update
如果有其他的查询操作也使用for update来查询Id=1的数据的话,那些查询会被挂起,一直到针对这条数据的更新操作完成从而释放这个行锁,代码才会继续执行。3、事务:锁是和事务相关的,因此通过BeginTransac ...
EFCore_全局查询筛选器
全局查询筛选器全局查询筛选器:EF Core会自动将这个查询筛选器应用于涉及这个实体类型的所有LINQ查询。场景:软删除、多租户。
用法向配置类添加builder.HasQueryFilter(b=>b.IsDeleted==false);
12345678public class ArticleConfig : IEntityTypeConfiguration<Article>{ public void Configure(EntityTypeBuilder<Article> builder) { builder.ToTable("T_Articles"); builder.HasQueryFilter(a => a.IsDeleted==false); }}
忽略全局筛选器ctx.Articles.IgnoreQueryFilters();
12345678910static void Main(string[] ...
EFCore_实体数据的状态
实体状态快照更改跟踪首次跟踪一个实体的时候,EF Core会创建这个实体的快照。执行SaveChanges()等方法时,EF Core将会把存储在快照中的值与实体的当前值进行比较。和DbContext有关系的实体、类都会生成快照。
实体的状态已添加(Added):DbContext正在跟踪此实体,但数据库中尚不存在该实体。未改变(Unchanged):DbContext正在跟踪此实体,该实体存在于数据库中,其属性值和从数据库中读取到的值一致,未发生改变。已修改(Modified):DbContext正在跟踪此实体,并存在于数据库中,并且其部分或全部属性值已修改。已删除(Deleted):DbContext正在跟踪此实体,并存在于数据库中,但在下次调用SaveChanges时要从数据库中删除对应数据。已分离(Detached):DbContext未跟踪该实体。
查询实体状态使用DbContext的Entry()方法来获取实体在EF Core的跟踪信息对象EntityEntry。EntityEntry类的State属性代表实体的状态,通过DebugView.LongView属性可以看到实体 ...
EFCore_原生SQL语句
执行原生非查询SQL语句可以自己写数据库语句而非使用linq进行转换。由于数据库语法的差异,所以可能无法跨越数据库使用。一般用于以下情况:非查询语句、实体查询、任意SQL查询。
简单使用使用dbCtx.Database.ExecuteSqlInterpolated()、dbCtx.Database.ExecuteSqlInterpolatedAsync()执行原生的非查询SQL语句。
123456static async Task Main(string[] args) { using(var ctx = new MyDbContext()) { await ctx.Database.ExecuteSqlInterpolatedAsync(@$"INSERT INTO t_articles (Title, Message) VALUES ('WBG对战T1', 'WBG与T1将于11月19日下午四点进行比赛');"); ...
EFCore_IQueryable
IQueryable与IEnumerable不同的Where方法1、对于普通集合和DbSet调用的Where方法,虽然用起来一样,但是“转到定义”后看到的是不同的方法。2、普通集合的版本(IEnumerable)是在内存中过滤(客户端评估),而IQueryable版本则是把查询操作翻译成SQL语句(服务器端评估)。如果强制使用IEnumerable的版本,两个方式会生成不同的SQL语句。Program.cs:
1234567891011 static void Main(string[] args) { using (var ctx = new MyDbContext()) { //IQueryable<Comment> comments = ctx.Comments; //IQueryable<Comment> cmts = comments.Where(c => c.Message.Contains("人性")); IEnume ...
EFCore_一对一与多对多
一对一采购申请订单——>采购订单订单——>快递单我将以订单——>快递单为例进行讲解。一对一关系必须显示地在其中一个实体类中声明一个外键属性。实体类:
123456789101112public class Delivery { public long Id { get; set; } public string CampanyName { get; set; } public string Number { get; set; } public Order Order { get; set; } public long OrderId { get; set; }//显式建立外键}public class Order { public long Id { get; set; } public string Name { get; set; } public ...
EFCore_一对多
EF Core一对多步骤1、实体类中关系属性2、FluentAPI关系配置3、使用关系操作
演示目的:数据库保存文章与评论,一篇文章对应多条评论1、实体类中关系属性
123456789101112public class Article { public int Id { get; set; } public string Title { get; set; } public string Message { get; set; } public List<Comment> Comments = new List<Comment> ();//实体类中关系属性}public class Comment { public int Id { get; set; } public string Message { get; set; } public Article TheArticle { ...
EFCore_一些注意事项
主键策略自增主键1、EF Core支持多种主键生成策略:自动增长、Guid、Hi/Lo算法等。2、自动增长优点:简单;缺点:数据库迁移以及分布式系统中比较麻烦;并发性能差。long、int等类型主键,默认是自增的。因为是数据库生成的值,所以SavaChanges后会自动把主键的值更新到Id属性。3、自增字段的代码中不能为Id赋值,必须保持默认值0,否则运行的时候会报错。
Guid主键1、Guid算法(或UUID算法)生成一个全局唯一的Id。适合于分布式系统,在进行多数据库数据合并时很简单。优点:简单、高并发效率比自增主键高、全局唯一;缺点:磁盘空间占用大。2、Guid值不连续。使用Guid类型做主键的时候,不能把主键设置为聚集索引。因为聚集索引是按照顺序保存主键的,因此用Guid做主键性能差。比如MySql的InnoDB引擎中主键是强制使用聚集索引的。有的数据库支持部分的连续Guid,比如SQLServer中的NewSequentialId(),但也不能解决问题。在SQLServer等中,不要把Guid主键设置为聚集索引;在MySQL中,插入频繁的表不要用Guid做主键。
1 ...
EFCore_FluentAPI
约定配置主要规则:1、表名采用DbContext中对应DbSet的属性名。2、数据表列的名字采用实体类属性的名字,列的数据类型采用和实体类属性类型最兼容的类型。3、数据表列的可空性取决于对应实体类属性的可空性。4、名字为Id 的属性为主键,如果主键为short、int、long类型,则默认采用自增字段,如果主键为Guid类型,则默认采用默认的Guid生成机制生成主键值。
两种配置方式1、Data Annotation把配置以特性(Annotation)的形式标注在实体类中。
12345678910[Table("T_Perosns")]public class Person { public int id { get; set; } [Required()] [MaxLength(100)] public string name { get; set; } public int age { get; set; } public string sex { ...














