关键词:
本文基于发稿时EF Core的最新版本5.0.
文章目录
1. 操作篇
快速开始
如何根据实体类生成模型
实体关系的配置
值转换器(Value Conversion)
数据库架构调整与数据迁移
2. 原理篇
3. 优化篇
4. 常见问题
4.1 怎么查看生成的sql
使用LogTo
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
optionsBuilder
.UseSqlServer(@"Server=(localdb)\\mssqllocaldb;Database=Blogging;Integrated Security=True")
.LogTo(Console.WriteLine, LogLevel.Information);
4.2 怎么直接执行sql
context.Database.ExecuteSqlRaw("UPDATE [Employees] SET [Salary] = [Salary] + 1000");
//防止sql注入方式四,直接构造DbParameter
var user = new SqlParameter("user", "johndoe");
var blogs = context.Blogs
.FromSqlRaw("EXECUTE dbo.GetMostPopularBlogsForUser @user", user)
.ToList();
详见【原理篇-数据查询原理】
4.3 怎么执行事务
using var context = new BloggingContext();
using var transaction = context.Database.BeginTransaction();
try
context.Blogs.Add(new Blog Url = "http://blogs.msdn.com/dotnet" );
context.SaveChanges();
context.Blogs.Add(new Blog Url = "http://blogs.msdn.com/visualstudio" );
context.SaveChanges();
var blogs = context.Blogs
.OrderBy(b => b.Url)
.ToList();
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
catch (Exception)
// TODO: Handle failure
事务失败会自动回滚,不需要手动操作。事务的更多用法,详见【原理篇-数据保存原理】
4.4 怎么使用数据库锁
4.4.1 乐观锁
实体上新增一个属性,标记为Timestamp:
[Timestamp]
public byte[] versionget;set;
然后把SaveChanges
用try-catch包裹起来 ,当有并发冲突时会抛出DbUpdateConcurrencyException
异常,然后进行处理 即可。
详见【原理篇-数据保存原理3.2节】
4.4.2 悲观锁
查询之后就锁住,禁止其他查询和修改,容易死锁,性能低。efcore不支持,可以借助ADO.NET的事务实现:
static void Main(string[] args)
using (SqlConnection conn = new SqlConnection(connstr))
conn.Open();
using (var tx = conn.BeginTransaction())
try
using (var selectCmd = conn.CreateCommand())
selectCmd.Transaction = tx;
//xlock:排它锁,ROWLOCK行锁
selectCmd.CommandText = "select * from T_Girls with(xlock,ROWLOCK) where id=1";
using (var reader = selectCmd.ExecuteReader())
if (!reader.Read())
Console.WriteLine("没有id为1的女孩");
return;
string bf = null;
if (!reader.IsDBNull(reader.GetOrdinal("BF")))
bf = reader.GetString(reader.GetOrdinal("BF"));
if (!string.IsNullOrEmpty(bf))//已经有男朋友
if (bf == myname)
Console.WriteLine("早已经是我的人了");
else
Console.WriteLine("早已经被" + bf + "抢走了");
Console.ReadKey();
return;
//如果bf==null,则继续向下抢
Console.WriteLine("查询完成,开始update");
using (var updateCmd = conn.CreateCommand())
updateCmd.Transaction = tx;
updateCmd.CommandText = "Update T_Girls set BF=@bf where id=1";
updateCmd.Parameters.Add(new SqlParameter("@bf", myname));
updateCmd.ExecuteNonQuery();
Console.WriteLine("结束Update");
Console.WriteLine("按任意键结束事务");
Console.ReadKey();
//事务提交之前你一直占有这行数据
tx.Commit();
catch (Exception ex)
Console.WriteLine(ex);
tx.Rollback();
Console.ReadKey();
4.5 导航属性的类型
如果是集合则可以为ICollection<T>
或List<T>
或HashSet<T>
4.6 主外键的默认命名规则
- 主键命名规则:符合
Id
、ID
、ClassnameId
、ClassnameID
这些规则的属性自动认为是主键 - 外键规则:
<导航属性名称><导航属性对应实体的主键属性名>
或<导航属性对应实体的主键属性名>
4.7 EF Core怎么知道SaveChanges
时哪些内容要提交到数据库?
通过Change tracking
实现的。当数据从数据库读取出来之后,efcore会创建数据的快照,调用保存时会与快照进行对比。详见【原理篇-更改跟踪原理】。
4.8 禁止自动给主键赋值
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BlogId get; set;
5. 一些“坑”
“坑”不一定是真坑,所以加了引号。
5.1 跟踪查询引起的问题
ef默认使用的是跟踪查询,会把查询出来的实体实例信息记录在跟踪器中。当下次查询返回了一个跟踪器中已记录(主键相同)的实体时,则会把记录的这个实体作为查询结果直接返回(虽然还是会执行一遍sql),而且不会用数据库中的值覆盖现有实体的值。所以以下代码可能会出乎你的意料:
var blog = context.Blogs.Single(b => b.Name == "fish");
blog.Url = "aa";
var b = context.Blogs.Single(b => b.Name == "fish");
Console.WriteLine(b.Url);
此时blog的url还是aa,虽然生成的sql可以看到明显有两次查询:
info: 2021/6/2 15:40:01.856 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(2) [b].[Id], [b].[Name], [b].[Url]
FROM [Blogs] AS [b]
WHERE [b].[Name] = N'fish'
info: 2021/6/2 15:40:01.862 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(2) [b].[Id], [b].[Name], [b].[Url]
FROM [Blogs] AS [b]
WHERE [b].[Name] = N'fish'
针对where的一个操作:
var orders = context.Orders.Where(o => o.Id > 1000).ToList();
var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToList();
此时的查询结果:order的id大于1000的数据,而不是大于5000的数据。因为在跟踪查询的情况下,filter里的导航属性会被认为已经加载完成。
因为这个问题的存在,所以有时候你会发现明明自己没有调用Include
,却也把子实体的数据给加载过来了。
以上问题产生的原因是:efcore只会维护同一实体的一个状态,如果同一个实体既是modified又是deleted,那么保存时就会出错(上面的原理篇-更改跟踪原理做了详细解释)。这个问题可以通过使用非跟踪查询AsNoTracking
解决。
var blog = context.Blogs.Single(b => b.Name == "fish");
blog.Url = "aa";
var b = context.Blogs.AsNoTracking().Single(b => b.Name == "fish");
Console.WriteLine(b.Url);
一文学会使用bazel构建c++项目(代码片段)
文章目录什么是Bazel?简介特点使用流程构建流程基本概念WORKSPACE(工作区)PACKAGE(包)TARGET(目标)LABEL(标签)BUILD(构建文件)DEPENDENCY(依赖项)实战环境搭建安装Baz 查看详情
一文学会使用bazel构建c++项目(代码片段)
文章目录什么是Bazel?简介特点使用流程构建流程基本概念WORKSPACE(工作区)PACKAGE(包)TARGET(目标)LABEL(标签)BUILD(构建文件)DEPENDENCY(依赖项)实战环境搭建安装Baz 查看详情
一文学会使用bazel构建c++项目(代码片段)
文章目录什么是Bazel?简介特点使用流程构建流程基本概念WORKSPACE(工作区)PACKAGE(包)TARGET(目标)LABEL(标签)BUILD(构建文件)DEPENDENCY(依赖项)实战环境搭建安装Baz 查看详情
一文学会-fiddler抓包快速实战(代码片段)
文章目录一、Fiddler介绍与安装Fiddler介绍Fiddler下载与安装二、WEB端抓包开启/关闭抓包初次配置验证是否可以正常抓包Filter请求过滤_过滤&筛选页签启用Filter只显示指定的请求只显示内网的Hosts[使用频率较少]只显示外网的Hosts[... 查看详情
一文学会open5gs和ueransim安装及使用(代码片段)
1环境准备VM配置(2台)①操作系统:Ubuntu18.04.6server(注意server版安装需要断网安装)②CPU:4③Memory:2G④网卡2块:一块使用NAT模式用于访问外网(同时用于WebUI访问),另一块用于VM间的通信... 查看详情
pycharm用着卡还收费!何不试试vscode!一文学会vscode使用python(代码片段)
一、前言刚开始学Python的小伙伴可能会觉得每次写Python打开Cmd或者idle有点烦躁,没有代码补全也没有格式提示等。所以直接上手了Pycharm。但pycharm专业版还收费,而且这软件还挺占内存!电脑配置不高的小伙伴就会感... 查看详情
springcloudconfig一文学会(代码片段)
目录1、简介2、正文2.1SpringCloudConfig+手动刷新2.2SpringCloudConfig+Git+WebHook实现自动刷新2.3SpringCloudConfig+Eureka2.4SpringCloudBus多端刷新1、简介传统配置的痛点:在以前的项目中,我们通过配置文件、操作系统变量、Jav... 查看详情
(转)一文学会用tensorflow搭建神经网络
一文学会用Tensorflow搭建神经网络 本文转自:http://www.jianshu.com/p/e112012a4b2d字数2259 阅读3168 评论8 喜欢11cs224d-Day6:快速入门Tensorflow本文是学习这个视频课程系列的笔记,课程链接是youtube上的,讲的很好,浅显易... 查看详情
一文学会express(代码片段)
文章目录Express安装基本使用中间件编写中间件客户端发送请求的方式解析body数据解析JSON格式解析urlencoded格式什么是x-www-form-urlencoded格式?urlencoded方法解析form-data格式解析非文件类型数据上传文件日志处理解析params和query动... 查看详情
一文学会calico及k8s网络策略入门
参考技术Acalico网络策略提供了一系列的策略能力,其中包括策略的顺序/优先级,拒绝规则和其它更灵活的匹配规则。kubernetes网络策略仅应用于Pod,而Calico网络策略可以应用于多种类型的终端,比如pods,VMs和主机接口等。而且,... 查看详情
一文带你学会使用yolo及opencv完成图像及视频流目标检测(上)|附源码(代码片段)
计算机视觉领域中,目标检测一直是工业应用上比较热门且成熟的应用领域,比如人脸识别、行人检测等,国内的旷视科技、商汤科技等公司在该领域占据行业领先地位。相对于图像分类任务而言,目标检测会更加复杂一些,不... 查看详情
一文学会k8s多master集群+keepalived高可用实战
参考技术AApiserver是kubernetes集群交互的入口,封装了核心对象的增删改查操作,提供了RESTFul风格的API接口,通过etcd来实现持久化并维护对象的一致性。所以在整个K8S集群中,Apiserver服务至关重要,一旦宕机,整个K8S平台将无法... 查看详情
一文学会calico网络自定义
参考技术ACalico支持多个容器网络选项,用于可伸缩性、网络性能和与现有基础设施的互操作性。不同的网络实现更适合不同的环境。Calico提供了几种不需要封装的基于IP路由的网络实现。如果您的部署需要封装,Calico提供覆盖网... 查看详情
一文学会springmvc表单标签(代码片段)
...专栏:国学周更-心性养成之路🥭本文内容:一文学会SpringMVC表单标签文章目录form标签input标签password标签checkbox标签checkboxes标签radiobutton与radiobuttons标签select与option/options标签 使用SpringMVC提供的表单标签可以让JSP... 查看详情
一文教你学会需求分析与管理
大家好,我是孙叫兽,本期给大家分享需求分析与管理,在项目开始或者需求整理时,这方面的知识显得尤为重要,常言道:良好的开始是成功的一半!1.需求的定义产品需求是在一定的时期,一定的场景中,无论是心理上还是... 查看详情
一文教你学会需求分析与管理
大家好,我是孙叫兽,本期给大家分享需求分析与管理,在项目开始或者需求整理时,这方面的知识显得尤为重要,常言道:良好的开始是成功的一半!1.需求的定义产品需求是在一定的时期,一定的场景中,无论是心理上还是... 查看详情
一文学会使用bazel构建c++项目(代码片段)
文章目录什么是Bazel?简介特点使用流程构建流程基本概念WORKSPACE(工作区)PACKAGE(包)TARGET(目标)LABEL(标签)BUILD(构建文件)DEPENDENCY(依赖项)实战环境搭建安装Bazel安装... 查看详情
python字体反爬之乐居字体反爬,一文看懂,一文学会(代码片段)
📢📢📢📢📢📢💗你正在阅读【梦想橡皮擦】的博客👍阅读完毕,可以点点小手赞一下🌻发现错误,直接评论区中指正吧📆橡皮擦的第672篇原创博客从订购之日起,案例5年... 查看详情