asp.net core系列 35 EF保存数据(2) -- EF系列结束
一.事务
(1) 事务接着上篇继续讲完。如果使用了多种数据访问技术,来访问关系型数据库,则可能希望在这些不同技术所执行的操作之间共享事务。下面示例显示了如何在同一事务中执行 ADO.NET SqlClient 操作和 Entity Framework Core 操作。
using (var connection = new SqlConnection(connectionString))
{
//使用ado.net 打开数据库连接
connection.Open(); //使用ado.net 开启事务
using (var transaction = connection.BeginTransaction())
{
try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery(); // Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options; using (var context = new BloggingContext(options))
{
//EF事务结合ado.net事务
context.Database.UseTransaction(transaction);
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
} // Commit transaction if all commands succeed, transaction will auto-rollback when disposed if either commands fails
transaction.Commit();
}
catch (System.Exception)
{
// TODO: Handle failure
}
}
}
(2) 使用 System.Transactions
如果需要跨大作用域进行协调,则可以使用分布式事务(跨库事务)TransactionScope,它可协调跨多个资源管理器的事务。存在于ADO.NET 中的System.Transactions命令空间。此功能是 EF Core 2.1 中的新增功能。虽然该功能在 .NET Framework 的 ADO.NET 提供程序之间十分常见,但最近才将 API 添加到 .NET Core,因此支持并未得到广泛应用。
//设置事务隔离级别IsolationLevel.ReadCommitted
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{ using (var connection = new SqlConnection(connectionString))
{
connection.Open(); try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery(); // Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options; using (var context = new BloggingContext(options))
{
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
} // Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
scope.Complete();
}
catch (System.Exception)
{
// TODO: Handle failure
}
}
}
二. 异步保存
关于使用异步的注意事项和优势,在第33篇 EF查询数据中有讲到。Entity Framework Core 提供了 DbContext.SaveChangesAsync() 异步替代了 DbContext.SaveChanges() 同步方法。下面是一个保存,使用异步示例
public static async Task AddBlogAsync(string url)
{
using (var context = new BloggingContext())
{
var blog = new Blog { Url = url };
context.Blogs.Add(blog);
await context.SaveChangesAsync();
}
}
三.不同上下文的实体状态判断
有时会使用一个上下文实例查询实体,然后使用其他上下文实例对其进行保存。 这通常在“断开连接”的情况下发生,例如 Web 应用程序,此情况下实体被查询、发送到客户端被修改、在请求中发送回服务器,然后进行保存。 在这种情况下,第二个上下文实例需要知道实体是新实体(应插入)还是现有实体(应更新)。
3.1标识新实体
下面介绍了几中方式确定是插入还是更新的实体情况:
(1)使用自动生成的键
可以理解为在数据库端设置ID键自增长,可以通过键值来判断是新增还是修改。
/// <summary>
///(1)使用键的内置方法来检查 true: 新增(上下文类中)
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool IsItNew( object entity)
=> !this.Entry(entity).IsKeySet; // (2)已知类型检查 true: 新增
public bool IsItNew(Blog blog)
=> blog.BlogId <= ; // b is false 修改实体
var blog = BloggingContext.Blogs.First();
bool b = BloggingContext.IsItNew(blog); //b is true 新增实体
var blog = new Blog() { Url = "www.baidu.com" };
bool b = BloggingContext.IsItNew(blog);
(2) 使用其它键
未自动生成键值时,需要使用其他某种机制来确定新实体。 有以下两种常规方法(查询实体 或 从客户端传递标志)。若要查询实体,只需使用 Find 方法, 例如下所示:
public static bool IsItNew(BloggingContext context, Blog blog)
=> context.Blogs.Find(blog.BlogId) == null;
3.2 保存单个实体
如果知道是需要插入还是需要更新,则可以相应地使用 Add 或 Update(之前是新增还是修改,是根据ChangeTracker跟踪器自动检测的,因为是同一个下下文而且实体有主键)如下所示:
public static void Insert(DbContext context, object entity)
{
context.Add(entity);
context.SaveChanges();
} public static void Update(DbContext context, object entity)
{
context.Update(entity);
context.SaveChanges();
}
如果实体不使用自动生成的键,则应用程序必须确定是应插入实体还是应更新实体:例如:
public static void InsertOrUpdate(BloggingContext context, Blog blog)
{
var existingBlog = context.Blogs.Find(blog.BlogId);
if (existingBlog == null)
{
context.Add(blog);
}
else
{
// SetValues 调用将根据需要,标记要更新的实体属性。原理是:要更新的实体与之前查询的实体进行比较,只会更新实际发生更改的列
context.Entry(existingBlog).CurrentValues.SetValues(blog);
}
context.SaveChanges();
}
四. 设置SQL Server IDENTITY列中的显式值
对于大多数情况,是由数据库生成自增长ID。如果要将显式值插入SQL Server IDENTITY列,需要在调用SaveChanges()之前,手动启用IDENTITY_INSERT。如下所示:
using (var context = new EmployeeContext())
{
context.Employees.Add(new Employee { EmployeeId = , Name = "John Doe" });
context.Employees.Add(new Employee { EmployeeId = , Name = "Jane Doe" }); context.Database.OpenConnection();
try
{
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees ON");
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees OFF");
}
finally
{
context.Database.CloseConnection();
}
}
参考文献
EF第三方扩展工具
asp.net core系列 35 EF保存数据(2) -- EF系列结束的更多相关文章
- ASP.Net Core 2.2 MVC入门到基本使用系列 (三)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- Asp.Net Core基于JWT认证的数据接口网关Demo
近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo.朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (二)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (一)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (四)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- asp.net core系列 34 EF保存数据(1)
一. 基本数据 每个EF上下文实例都有一个 ChangeTracker(更改跟踪器),它负责跟踪需要写入数据库的更改. 当更改实体类的实例时(修改属性,删除实例,新建实例等),这些更改会记录在 Cha ...
- ASP.NET Core 2.2 附加的数据文件存放在项目文件夹内
在ASP.NET 4.x中(包括ASP.NET MVC 5),可以通过附加数据库文件的方式,将数据库保存在项目的文件中.这种方式对于不同时段需要更换计算机(白天办公室,晚上家里)开发时带来好处. 而. ...
- Asp .net core api+Entity Framework 实现数据的存取到数据库中
最近在学dotNetCore 所以尝试了一下api 这个功能 不多说了大致实现如下 1.用vs2017建立一个Asp.net Core Web 应用程序 在弹出的对话框中选择 Web API 项目名 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (三)(转)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
随机推荐
- Android中Adapter类的使用 “Adapter”
Adapter用来把数据绑定到扩展了AdapterView类的视图组(例如:ListView或Gallery).Adapter负责创建代表所绑定父视图中的底层数据的子视图. 可以创建自己的Adapte ...
- 32位二进制IP地址与十进制IP地址互相转换
代码: import java.util.List; import java.util.ArrayList; import java.util.Scanner; public class Transf ...
- 将Redhat,CentOS,Ubuntu虚拟机的IP设为静态IP的方法
一般在主机上创建的虚拟机默认是通过DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)网络协议来动态生成的,这样会导致你安装的虚拟机的IP地址是动态变化 ...
- Elasticsearch 滚动重启 必读
关键词:elasticsearch , es , 滚动重启 , 禁止分片 由于之前es GC没有怎么调优,结果今天被大量scroll查询查挂了,GC 卡死了.然后为了先恢复给业务使用,也没什么其他办法 ...
- ES8 async/await语法
Async/await的主要益处是可以避免回调地狱(callback hell)问题 Chromium JavaScript引擎 从v5.5开始支持async/await功能,Chromium Jav ...
- weex 学习: 添加图标(使用阿里吧吧-icon)
添加图标(使用阿里吧吧-icon) <text slot="left" class="header-left"></text> i ...
- macOS实现视频转音频以及音频拼接
macOS实现视频转音频以及音频拼接 ffmpeg 的安装 终端输入以下指令: brew install ffmpeg 视频转音频 终端输入以下指令: ffmpeg -i 视频名称.flv -vn - ...
- 约瑟夫环问题 --链表 C语言
总共有m个人在圆桌上,依次报名,数到第n个数的人退出圆桌,下一个由退出人下一个开始继续报名,循环直到最后一个停止将编号输出 #include <stdio.h>#include <s ...
- 最小生成树 kruskal算法&prim算法
(先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...
- DB2 数据库的安装配置及监控
一.DB2简介 IBM公司研制的一种关系型数据库系统.DB2主要应用于大型应用系统,具有较好的可伸缩性,可支持从大型机到单用户环境,应用于OS/2.Windows等平台下. DB2提供了高层次的数据利 ...