博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
asp.net core系列 35 EF保存数据(2) -- EF系列结束
阅读量:5060 次
发布时间:2019-06-12

本文共 5753 字,大约阅读时间需要 19 分钟。

原文:

一.事务

  (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
() .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.ReadCommittedusing (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
() .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键自增长,可以通过键值来判断是新增还是修改。

///         ///(1)使用键的内置方法来检查 true: 新增(上下文类中)        ///         ///         /// 
public bool IsItNew( object entity) => !this.Entry(entity).IsKeySet;    // (2)已知类型检查 true: 新增    public bool IsItNew(Blog blog)    => blog.BlogId <= 0; // 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 = 100, Name = "John Doe" });    context.Employees.Add(new Employee { EmployeeId = 101, 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

 

posted on
2019-03-01 15:37 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10456748.html

你可能感兴趣的文章
HTML块级元素和行内元素
查看>>
[Security_Android] exploit of Ad for android app代码分析
查看>>
Python学习-37.Python中的正则表达式
查看>>
洛谷 1485 火枪打怪
查看>>
Luogu4609 FJOI2016 建筑师 第一类斯特林数
查看>>
Docker从入门到安装MySQL
查看>>
ndk开发教程以及问题解决方案
查看>>
职业资格证书查询
查看>>
JMeter学习-005-JMeter 主要组件概要介绍及执行顺序(转载)
查看>>
墨菲定理实战
查看>>
自定义AutoCompleteTextView
查看>>
LINQ之路(2):LINQ to SQL本质
查看>>
(转载)winform图片标尺控件
查看>>
day 56 linux的安装python3 ,虚拟环境,mysql ,redis
查看>>
collectd+infludb+grafana实现tomcat JVM监控
查看>>
【转】Nginx配置location总结及rewrite规则写法
查看>>
2016年云堆栈的市场增长状况
查看>>
html超文本标记语言的由来
查看>>
PAT 1095 Cars on Campus
查看>>
cesium编程入门(七)3D Tiles,模型旋转
查看>>