EF实体框架之CodeFirst七
前面的6篇博客基本把Code First学习的差不多了,今天这篇学习下code first中的并发控制和事务,基本也快学完了,顶多就差数据迁移。
在数据库中也是有锁和事务的概念,在C#中也是存在,当然code first也是必要要有的。对于什么是并发、什么是锁和事务,它们的特性是什么这些概念性的就不一一列举。因为这些要是发散的学习就涉及到好多的知识点。并发能联想到多线程,多线程能联想到同步异步,同步异步操作系统,等等。知识都是连贯着的。有了并发那就有不并发的情况,想让不并发,那用什么呢?那就要用锁。说起锁又想起锁的类型、粒度、死锁等。什么悲观锁、乐观锁、粒度上又分单元格级、行级、表级等。总的来说想弄明白C#是很不容易的,担负着打光棍的风险,把青春放在了敲代码上。上面算是开场白一些不正经的,下面开始说正经的。
一、并发控制
1.锁分悲观锁和乐观锁。
在code first中使用的是乐观锁。至于什么是悲观锁,大家应该都用过版本控制软件,VSS中有签入签出,当被迁出的时候其他人是修改不了的,这种就是可以理解为悲观锁。而在svn中当一个文件被迁出时,其他人还可以修改,之前commit的时候根据版本合并就OK,这种可以理解为乐观锁。
2.锁的粒度
code first在锁的粒度上也分为两种。一是行级一个单元格级及属性集。
1).行级
使用Timestamp来控制每行的并发。一张表中只能有一个Timestamp的字段(一个类只能有一个Timestamp的属性).
Data Annotations中用Timestamp来标识设置并发控制字段,标识为Timestamp的字段必需为byte[]类型。
public class Person
{
public int PersonId { get; set; }
public int SocialSecurityNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Money { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
var person = new Person
{
FirstName = "Cui",
LastName = "YanWei",
SocialSecurityNumber =
};
//新增一条记录,保存到数据库中
using (var con = new EFCodeFirstDbContext())
{
con.Persons.Add(person);
con.SaveChanges();
} var firContext = new EFCodeFirstDbContext();
//取第一条记录,并修改一个字段:这里是修改了FirstName
//先不保存
var p1 = firContext.Persons.FirstOrDefault();
p1.FirstName = "CuiA"; //再创建一个Context,同样取第一条记录,修改LastName字段并保存
using (var secContext = new EFCodeFirstDbContext())
{
var p2 = secContext.Persons.FirstOrDefault();
p2.LastName = "Ivan";
secContext.SaveChanges();
}
try
{
firContext.SaveChanges();
Console.WriteLine(" 保存成功");
}
catch (DbUpdateConcurrencyException ex)
{
Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失败");
}
Console.Read();
在上面的代码中首先是新增一个Person对象,SaveChanges()保存到数据库。然后将Person对象获取出来改变FirstName,但此时并没有SaveChanges()保存到数据库.然后呢有将该对象取出来,修改LastName并SaveChanges()保存到数据库,此时再将上面的修改FirstName的保存到数据库,运行时会抛出异常。这是为什么呢?
可以看下下面的三个截图:



上面的3个截图,第一个sql是最先执行,然后是第二个,不过这里要注意下两个sql的binary字段,两个都是一样的,但是最后存在数据库的可是不一样,其实当第一个sql执行完时binary字段变成了也就是数据库现在存在的值,但是第二个sql执行时还是用的之前的值,所以就更新失败抛出异常。这就是Timestamp的机制。
2).列级
Data Annotations中用ConcurrencyCheck来标识控制列的并发。此时可以先把上面的Person类中的Timestamp注释掉。在SocialSecurityNumber属性上添加约定。
public class Person
{
public int PersonId { get; set; } [ConcurrencyCheck]
public int SocialSecurityNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Money { get; set; }
//[Timestamp]
public byte[] RowVersion { get; set; }
}
我们将SocialSecurityNumber(社会保险号)标识为开放式并发。
var person = new Person
{
FirstName = "Cui",
LastName = "YanWei",
SocialSecurityNumber =
};
//新增一条记录,保存到数据库中
using (var con = new EFCodeFirstDbContext())
{
con.Persons.Add(person);
con.SaveChanges();
}
var firContext = new EFCodeFirstDbContext();
//取第一条记录,并修改一个字段:这里是修改了SocialSecurityNumber=123
//先不保存
var p1 = firContext.Persons.FirstOrDefault();
p1.SocialSecurityNumber = ;
//再创建一个Context,同样取第一条记录,修改SocialSecurityNumber=456并保存
using (var secContext = new EFCodeFirstDbContext())
{
var p2 = secContext.Persons.FirstOrDefault(); p2.SocialSecurityNumber = ;
secContext.SaveChanges(); }
try
{
firContext.SaveChanges();
Console.WriteLine(" 保存成功");
}
catch (DbUpdateConcurrencyException ex)
{
Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失败");
}
Console.Read();
下面还是3张截图.



和Timestamp类似,3个截图的第一个sql是第二个更改操作的数据库上下文更改执行的sql,第二个是第一个更改操作的数据库上下文更改执行的sql,where语句中增加了SocialSecurityNumber,由于第一个sql执行之后SocialSecurityNumber已经改变,第二个sql还是使用旧的SocialSecurityNumber,所以更新失败。
二、事务
1.默认事务处理
EF的默认行为是,无论何时执行任何涉及Create,Update或Delete的查询,都会默认创建事务。当DbContext类上的SaveChanges()方法被调用时,事务就会提交。
2.分布式事务
对于分布式事务可以想到TransactionScope,code first中分布式事务意味着多个DbContext,由于EF默认就是事务处理,所以只需关注分布式的事务,对于分布式事务的应用需要开启window服务,这个日后会具体总结。注意要引入类库:
using System.Transactions;
using (var ts = new TransactionScope(TransactionScopeOption.Required))
{
//db数据库上下文操作
ts.Complete();
}
3.EF6管理事务
从EF 6起,EF在DbContext对象上提供了Database.BeginTransaction()方法,当使用上下文类在事务中执行原生SQL命令时,这个方法特别有用。
using (var db = new EFCodeFirstDbContext())
{
using (var trans = db.Database.BeginTransaction())
{
try
{ //执行sql
db.SaveChanges(); trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
}
}
EF实体框架之CodeFirst七的更多相关文章
- EF实体框架之CodeFirst四
在EF实体框架之CodeFirst二中也提到数据库里面一般包括表.列.约束.主外键.级联操作.实体关系(E-R图).存储过程.视图.锁.事务.数据库结构更新等.前面几篇博客把表.存储过程.视图这些算是 ...
- EF实体框架之CodeFirst一
对于SQL Server.MySql.Oracle等这些传统的数据库,基本都是关系型数据库,都是体现实体与实体之间的联系,在以前开发时,可能先根据需求设计数据库,然后在写Model和业务逻辑,对于Mo ...
- EF实体框架之CodeFirst五
上一博客学习了下基本的约定配置,留下几个遗漏的,这篇就是学习下遗漏一复杂类型. 一.什么是复杂类型? 书中说道:“复杂类型也可视作值类型(?)可以作为附加属性添加到其他类.复杂类型与实体类型的区别在于 ...
- EF实体框架之CodeFirst二
在codefirst一中也说了Mapping是实体与数据库的纽带,model通过Mapping映射到数据库,我们可以从数据库的角度来分析?首先是映射到数据库,这个是必须的.数据库里面一般包括表.列.约 ...
- EF实体框架之CodeFirst八
前面七篇基本把Code First学习了一下,不过code first中会出现一个问题,就是数据迁移的问题. 一.数据准备 还是在前面的demo上修改,这次使用Province和City类. publ ...
- EF实体框架之CodeFirst六
上午的时候把复杂类型学习了一下,想着趁着周六日把Code First学习完,所以下午还是把Code First中的关系学习下.在数据库中最重要的恐怕就是E-R图了,E-R体现了表与表直接的关系.使用C ...
- EF实体框架之CodeFirst三
前两篇博客学习了数据库映射和表映射,今天学习下数据库初始化.种子数据.EF执行sql以及执行存储过程这几个知识. 一.数据库初始化策略 数据库初始化有4种策略 策略一:数据库不存在时重新创建数据库 D ...
- 【MVC 1】MVC+EF实体框架—原理解析
导读:在之前,我们学过了三层框架,即:UI.BLL.DAL.我们将页面显示.逻辑处理和数据访问进行分层,避免了一层.两层的混乱.而后,我们又在经典三层的基础上,应用设计模式:外观.抽象工厂+反射,使得 ...
- C#.Net EF实体框架入门视频教程
当前位置: 主页 > 编程开发 > C_VC视频教程 > C#.Net EF实体框架入门视频教程 > kingstone金士顿手机内存卡16G仅65元 1.EF实体框架之增加查 ...
随机推荐
- 应用Spring MVC发布restful服务是怎样的一种体验
摘要:“约定优于配置”这是一个相当棒的经验,SOAP服务性能差.基于配置.紧耦合,restful服务性能好.基于约定.松耦合,现在我就把使用Spring MVC发布restful服务的 ...
- freemarker如何遍历HashMap
查询资料有以下两种方法: 1. <#if appMap?exists> <#list appMap?keys as key> key:${key} value:${appMap ...
- Android Listener侦听的N种写法
Android中,View的Listener方法,在是否使用匿名类匿名对象时,有各种不同的写法. OnClickListener和其他Listener方法一样,都是View类的接口,重载实现后就能使用 ...
- 从mysql数据表中随机取出一条记录
核心查找数据表代码: ; //此处的1就是取出数据的条数 但这样取数据网上有人说效率非常差的,那么要如何改进呢 搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据. S ...
- java自带命令工具
jstat,这个工具很强大,可以监测Java虚拟机GC多方面的状态,具体参数含义参见此链接: ./jstat -gc 84012 1000 3 S0C S1C S0U S1U ...
- C++ new(3)
转载自:http://www.builder.com.cn/2008/0104/696370.shtml “new”是C++的一个关键字,同时也是操作符.关于new的话题非常多,因为它确实比较复杂,也 ...
- [嵌入式开发板]iTOP-4412开发板linux 系统存储空间的修改
平台:iTOP-4412开发板 这里我们以修改成 1G 存储空间为例来讲解修改方法, 如果需要改 成其他大小的存储空间,参照此方法修改即可. 首先连接好 iTOP-4412 开发板的调试串口到 pc ...
- c++获取sqlite3数据库表中所有字段的方法
常用方法: 1.使用sqlite3_get_table函数 2.获取sqlite创建表的sql语句字符串,然后进行解析获取到相应的字段 3.采用配置文件的方式,将所有字段名写入配置文件 方法1:使用s ...
- T-SQL 语句创建Database的SQL mirroring关系
1 证书部分:principle 和 secondary 端执行同样操作,更改相应name即可 USE master; --1.1 Create the database Master Key, if ...
- codeforces 577B B. Modulo Sum(水题)
题目链接: B. Modulo Sum time limit per test 2 seconds memory limit per test 256 megabytes input standard ...