C# 数据操作系列 - 8. EF Core的增删改查
0.前言
到目前为止,我们看了一下如何声明EF Core的初步使用,也整体的看了下EF Core的映射关系配置以及导航属性的配置。
这一篇,我带大家分享一下,我在工作中需要的EF Core的用法。
1. 初始化
在实际开发中,一般都是先设计好数据表再进行开发,所以很少用到EF Core的数据迁移功能。所以EF Core的初始化,一般也指的是EF Core上下文初始化。
1.1 连接字符串
我们通过前面的文章知道,EF Core在上下文初始化的时候,都需要一个链接字符串。如果在不考虑后续变更或者上下文的复用性,可以直接在自定义Context里重写OnConfiguring方法中定义。
如果需要后续变更,那么就需要在创建自定义EF Core 上下文类的时候,为之添加一个连接字符串的属性或者字段,以方便初始化的时候指定。实例:
public class DefaultContext : DbContext
{
private string Connection { get; set; } = "Data Source=./blogging1.db";
public DefaultContext(string connection)
{
Connection = connection;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(Connection);
}
这样一来,我们在后续使用的时候,就可以指定连接字符串了。当然了,如果有小伙伴有更好的方法也可以分享出来呀。
1.2 配置文件的加载或者实体对象的托管
如果我们不使用配置文件的话,就必须在EF Core的上下文类里添加一个类型是DbSet<T>的属性。继续延续上面的实例:
public class SingleModel
{
public int Id { get; set; }
public int TargetId { get; set; }
public SingleTargetModel SingleTarget { get; set; }
}
public class SingleTargetModel
{
public int Id { get; set; }
public SingleModel Single { get; set; }
}
public class DefaultContext : DbContext
{
// 其余代码参见 1.1 DefaultContext
public DbSet<SingleModel> Singles { get; set; }
public DbSet<SingleTargetModel> Targets { get; set; }
}
以上也就是这一小节标题中的实体对象的托管。我没找到EF Core官方文档中对于这种方式的称呼,所以我就悄悄的抢注了一下为托管。
如果我们使用Config类(也就是 《C# 数据操作系列 - 7. EF Core 导航属性配置》中介绍的配置类)的话,需要在EF Core中应用配置,具体是:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new SingleModelConfig());
modelBuilder.ApplyConfiguration(new SingleTargeModelConfig());
}
在使用的时候,可以直接:
var context = new DefaultContext("Data Source=demo.db");
var t1 = context.Set<SingleTargetModel>().First();
即使用DbContext.Set<T>,可以获取到一个数据加载集,当然也可以结合实体类的托管来一起使用。
那么为什么,我推荐使用配置类加载吗?
因为在实际开发中,一个完整的程序或者网站实体类都会大于10,而这些如果使用属性的形式会非常多,不利于实际开发。而且,EF Core可以通过 Assembly 方式整体加载配置文件。再者,为了保证ORM中的O不受其他因素的影响。也就是说,如果使用注解形式配置映射关系,那么势必会造成影响。
当然了,使用配置文件必然会导致项目的类增多,而且大量的重复类可能会出现。当然了,如果考虑到这个问题的话,可以试试写一个项目代码生成器哦,专门用来处理这些差不多的类。
咳咳,总而言之,使用配置文件利大于弊,所以我推荐使用配置文件对关系进行配置。
2. 数据变化
换句话说,嗯,也就是增删改。在数据增删这两方面,EF Core没有太多需要注意的地方。不过如果有导航属性的话,在新增的时候,EF Core会自动检索导航属性的另一端是否需要新增到数据库中,如果需要新增的话,EF Core会自动标记为新增的。
而删除,如果在配置导航属性时,没有设置级联删除,删除当前元素,如果另一端的外键是可空类型的,并不会删除导航属性另一端的元素只会设置外键指向为NULL,如果另一端外键是不可空的,那么就会同时删除。如果需要修改,可以使用以下方法修改,在配置导航属性的时候:
OnDelete(DeleteBehavior.Cascade);
对于可为NULL的外键来说,枚举DeleteBehavior的值起以下作用:
行为名称 | 对内存中的依赖项/子项的影响 | 对数据库中的依赖项/子项的影响 |
---|---|---|
Cascade | 删除实体 | 删除实体 |
ClientSetNull(默认) | 外键属性设置为 null | None |
SetNull | 外键属性设置为 null | 外键属性设置为 null |
Restrict | None | None |
而对于不可为NULL的外键来说,枚举DeleteBehavior的值起以下作用:
行为名称 | 对内存中的依赖项/子项的影响 | 对数据库中的依赖项/子项的影响 |
---|---|---|
Cascade(默认) | 删除实体 | 删除实体 |
ClientSetNull | SaveChanges 引发异常 | None |
SetNull | 引发 SaveChanges | SaveChanges 引发异常 |
Restrict | None | None |
而对于数据的修改,EF Core的做法是通过监控实体的ChangeTracker来实现对数据实体的状态更新。也就是说,如果你从EF Core的上下文获取了一个实体对象,对这个对象的某些值进行了修改。这时候EF Core其实已经记录了这个对象的修改。不需要我们额外的调用修改方法(因为根本没有Update方法)。
EF Core在我们调用 SaveChanges 会把缓存的所有更改(增、删、改)都推送给数据库。如果有一条数据变更因为数据库校验或者其他约束没有通过,就会报错,同时撤销所有已推送的变更并取消后续变更的推送。
从数据库的角度来看,EF Core在SaveChanges的过程中是以事务的形式推送给数据库的。如果出错,那么事务就会回滚。
所以一般情况下,EF不需要开启事务。
3.花样查询
EF Core 支持Linq查询,所以在查询的时候可以使用Linq进行。简单示例如下:
var context = new DefaultContext("Data Source=demo.db");
var results = from t in context.Set<SingleTargetModel>()
select t;
当然,也可以使用方法链的形式传入一个Expression<Func<T,bool>> 类型的表达式。
var results = context.Set<SingleTargetModel>().Where(t=>true);
看到这里了,可能会有疑问了,这明明很简单呀。是的,如果只是查询,自然简单。
那么,结合排序、分页之后呢?先来看看排序是怎么实现的吧。
在查询表达式写法中,排序应该这样的写的:
var results = from t in context.Set<SingleTargetModel>()
orderby t.Id //descending 如果降序则取消注释
select t ;
方法链的形式是:
var results = context.Set<SingleTargetModel>().Where(t=>true).OrderBy(t=>t.Id);
分页只能通过方法链的形式进行分页,这里提供一个分页的工具方法:
public static IQueryable<T> Paging<T>(IQueryable<T> source,int pageIndex,int pageSize)
{
return source.Skip(pageSize * (pageIndex - 1)).Take(pageSize);
}
这里用到的是 Skip(int count) 表示忽略数据集的前count条记录,Take(int count)取得数据集的前count条记录。
EF Core在调用 ToList的时候,会将已调用的方法和Linq转换成SQL语句,并正式向数据库发起查询。如果出现了在Linq中调用三方方法或者自己写的工具方法的话,可能会提示不受支持。
如果使用的Linq表达式,则没关系,EF Core在遇到这种情况的时候,会把数据库里所有数据都加载到上下文中,再执行后续的查询等操作。
所以,为了高效的查询,在执行查询的时候,最好使用简单的查询条件。
4. 后续
EF Core整体使用已经介绍完了,当然照例是普通工程级的内容。下一篇我给大家介绍一下EF Core剩下一些边角料,嗯。如果要深挖代码的话,得以后有机会了。
数据访问系列,EF Core 篇即将到一段落。待EF Core篇完成后,将带领一起去探索 Nhibernate和Dapper,SqlSugar这三个ORM框架。
更多内容烦请关注我的博客《高先生小屋》
C# 数据操作系列 - 8. EF Core的增删改查的更多相关文章
- C# 数据操作系列 - 6 EF Core 配置映射关系
0. 前言 在<C# 数据操作系列 - 5. EF Core 入门>篇中,我们简单的通过两个类演示了一下EF增删改查等功能.细心的小伙伴可能看了生成的DDL SQL 语句,在里面发现了些端 ...
- C# 数据操作系列 - 9. EF Core 完结篇
0.前言 <EF Core>实际上已经可以告一段落了,但是感觉还有一点点意犹未尽.所以决定分享一下,个人在实际开发中使用EF Core的一些经验和使用的扩展包. 1. EF Core的异步 ...
- C# 数据操作系列 - 5. EF Core 入门
0.前言 上一章简单介绍了一下ORM框架,并手写了一个类似ORM的工具类.这一章将介绍一个在C#世界里大名鼎鼎的ORM框架--Entity Framework的Core版. Entity Framew ...
- C# 数据操作系列 - 7. EF Core 导航属性配置
在上一篇,大概介绍了Entity Framework Core关于关系映射的逻辑.在上一篇中留下了EF的外键映射没有说,也就是一对一,一对多,多对一,多对多的关系等.这一篇将为大家细细分析一下,如何设 ...
- Entity - 使用EF框架进行增删改查 - 模型先行
模型先行:先创建数据库实体模型,然后再进行数据库的增删改查. 基本步骤是不变的,可参照 <Entity - 使用EF框架进行增删改查 - 数据库先行> 其中的不同是,在创建数据库实体模型的 ...
- ASP.NET CORE系列【二】使用Entity Framework Core进行增删改查
介绍 EntityFrameworkCore EF core 是一个轻量级的,可扩展的EF的跨平台版本.对于EF而言 EF core 包含许多提升和新特性,同时 EF core 是一个全新的代码库,并 ...
- ASP.NET CORE系列【三】使用Entity Framework Core进行增删改查
身份验证 以前我们熟悉的web.config中配置的form验证,现在没有了.我们来看看在Core里面如何配置: 首先需要NuGet安装一个包:Microsoft.AspNetCore.Authent ...
- MySQL数据库学习笔记(九)----JDBC的ResultSet接口(查询操作)、PreparedStatement接口重构增删改查(含SQL注入的解释)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- 我来讲讲在c#中怎么进行xml文件操作吧,主要是讲解增删改查!
我把我写的四种方法代码贴上来吧,照着写没啥问题. 注: <bookstore> <book> <Id>1</Id> <tate>2010-1 ...
随机推荐
- BUAA_OO 第一单元总结
1.简单多项式求导 第一次作业的难点,我认为是对输入的预处理,尤其是正则表达式的使用.这次作业的思路是:首先将表达式进行预处理,(由于题目中要求不会有空格产生的WF,所以可以放心大胆的消除空格). 消 ...
- thinkphp--导入导出xls文件
/** * 数组转xls格式的excel文件 * @param array $data 需要生成excel文件的数组 * @param string $filename 生成的excel文件名 * 示 ...
- 取 token 并查看 container 信息
curl -i -k \ -H "Content-Type: application/json" \ -d ' { "auth": { "identi ...
- 部署企业LNMP架构搭建bbs
部署企业LNMP架构 1===============部署Nginx 2===============安装及部署Mysql数据库 3===============安装PHP解析环境 4======== ...
- Pytorch使用PIL的读取单张图片并显示
1. Image.open(fp, mode="r") 调用此方法需要引入头文件:from PIL import Image. 参数说明: fp:图片路径,可为绝对路径或相对路径. ...
- Centos下安装Docker,并配置国内docker源
Centos下安装Docker 替换为国内的yum源(可选): mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.re ...
- C++如何求程序运行时间
C++中常用clock()函数求运行时间,返回值类型为clock_t,返回值是程序运行到本次调用clock()函数经过的clock数,头文件为<time.h>. 用法: 1.求开始时间s= ...
- MacBook Pro装Win7后喇叭没有声音
将MacBook的系统由XP改为Win7 64位后,发现喇叭没有声音了,装了bootcamp并升级到3.2版本都无济于事,google了下,发现还是驱动的问题,Win7下在设备管理器中看到声卡为Hig ...
- 数学--数论--HDU 2582 F(N) 暴力打表找规律
This time I need you to calculate the f(n) . (3<=n<=1000000) f(n)= Gcd(3)+Gcd(4)+-+Gcd(i)+-+Gc ...
- spring cloud系列教程第一篇-介绍
spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...