一.事务

  (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();
}
}

参考文献

  TransactionScope介绍

  EF第三方扩展工具

asp.net core系列 35 EF保存数据(2) -- EF系列结束的更多相关文章

  1. ASP.Net Core 2.2 MVC入门到基本使用系列 (三)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  2. Asp.Net Core基于JWT认证的数据接口网关Demo

    近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo.朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对 ...

  3. ASP.Net Core 2.2 MVC入门到基本使用系列 (二)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  4. ASP.Net Core 2.2 MVC入门到基本使用系列 (一)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  5. ASP.Net Core 2.2 MVC入门到基本使用系列 (四)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  6. asp.net core系列 34 EF保存数据(1)

    一. 基本数据 每个EF上下文实例都有一个 ChangeTracker(更改跟踪器),它负责跟踪需要写入数据库的更改. 当更改实体类的实例时(修改属性,删除实例,新建实例等),这些更改会记录在 Cha ...

  7. ASP.NET Core 2.2 附加的数据文件存放在项目文件夹内

    在ASP.NET 4.x中(包括ASP.NET MVC 5),可以通过附加数据库文件的方式,将数据库保存在项目的文件中.这种方式对于不同时段需要更换计算机(白天办公室,晚上家里)开发时带来好处. 而. ...

  8. Asp .net core api+Entity Framework 实现数据的存取到数据库中

    最近在学dotNetCore 所以尝试了一下api 这个功能 不多说了大致实现如下 1.用vs2017建立一个Asp.net  Core Web 应用程序 在弹出的对话框中选择 Web API 项目名 ...

  9. ASP.Net Core 2.2 MVC入门到基本使用系列 (三)(转)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

随机推荐

  1. mac环境下jdk配置

    查看mac下jdk路径 当在Mac下安装完Java运行环境,而又没有添加JAVA_HOME变量的时候,我们如何得到JAVA_HOME变量的路径呢?直接在home目录下执行命令:/usr/libexec ...

  2. MySql由于编码问题,存储过程执行出错。

    在存储过程后面加了一段话.红色部分 DELIMITER $$ USE `mysql_wispeed01-test1`$$ DROP PROCEDURE IF EXISTS `sp_crebillno` ...

  3. BZOJ1173 CDQ分治 笔记

    目录 二维数据结构->cdq 预备知识 T1: 二维树状数组 T2:cdq分治 bzoj1176 mokia:Debug心得 一类特殊的CDQ分治 附: bzoj mokia AC代码 二维数据 ...

  4. 数据分析 大数据之路 四 numpy 2

    NumPy 数学函数 NumPy 提供了标准的三角函数:sin().cos().tan(import numpy as np a = np.array([0,30,45,60,90])print (' ...

  5. URI ,URL 和 URN

    URI : 统一资源标识符,用来唯一标识互联网资源,包括URL和URN URL:统一资源定位器 包含: 协议,域名,端口,路由,参数,hash https://i.cnblogs.com/EditPo ...

  6. 在VB中动态执行VBS代码,可操控窗体控件

    通过执行一段VBS代码来操控窗体内的控件也可以使用AddObject方法添加自己的类,那么在动态VBS代码中也一样可以使用在增加程序扩展性或是有脚本化需求的时候,这个方法还是不错的. Option E ...

  7. margin与padding的bug

    1.在页面布局时,值对于块元素来说,相邻的两个兄弟块元素间的margin-top与上一个兄弟的margin-bottom重合时, 解决办法:对其中一个块元素中设置    display:inline- ...

  8. TCP协议中是如何保证报文可靠传输的

    1.什么是TCP的可靠传输 它向应用层提供的数据是无差错的.有序的.无丢失的,换言之就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的. 2.TCP保证可靠传输的办法有哪些? TCP采用 ...

  9. 移动端 rem适配方法

    rem适配 一, 网易适配方法         屏幕宽度/设计稿rem宽度=页面动态font-size值(如:375/7.5=50)         document.documentElement. ...

  10. cf 1142 C

    忽然觉得这个题很有必要写题解. 移项 y-x^2 = bx+c 那么其实就是找有多少条直线上方没有点 所以就是一个上凸壳有多少条直线/点. 绝妙啊!!!! 太妙了啊!!!! 神乎其技卧槽!!! (我是 ...