LINQ(数据库操作增、删、改及并发管理)
本文将演示如何通过 Entity Framework 数据模型创建、修改、删除数据库记录。
Customer cust = new Customer()
{
CustomerID = "LAWN",
CompanyName = "Lawn Wranglers",
ContactName = "Mr. Abe Henry",
ContactTitle = "Owner",
Address = "1017 Maple Leaf Way",
City = "Ft. Worth",
Region = "TX",
PostalCode = "",
Country = "USA",
Phone = "(800) MOW-LAWN",
Fax = "(800) MOW-LAWO"
}; NorthwindEntities db = new NorthwindEntities();
db.Customers.AddObject(cust);
db.SaveChanges();
可以多次 AddObject()后调用一次 SaveChanges() 全部写入数据库。
1. 创建部分加载的实体类
在之前的示例里,我们调用了 Customer 实体类的默认构造函数,它创建的实例没有加载任何数据。不过,我们还可以通过在构造函数里指定必须字段的值来减少数据库错误的风险。
每个实体类都有一个名为 CreateT 的工厂方法,例如,Customer 的实体类的工厂方法是 CreateCustomer 。看下面示例:
Customer cust = Customer.CreateCustomer("LAWN", "Lawn Wranglers");
cust.ContactName = "Mr. Abe Henry";
cust.ContactTitle = "Owner";
cust.Address = "1017 Maple Leaf Way";
cust.City = "Ft. Worth";
cust.Region = "TX";
cust.PostalCode = "";
cust.Country = "USA";
cust.Phone = "(800) MOW-LAWN";
cust.Fax = "(800) MOW-LAWO";
NorthwindEntities db = new NorthwindEntities();
db.Customers.AddObject(cust);
db.SaveChanges();
我们倾向于使用默认构造函数,因为可以在一条语句里指定属性的值,但是如果你经常会忘记给必需的字段赋值,那么工厂方法对你就非常有用。
2. 插入关联的实体
可以用实体类的导航属性创建一组关联的对象,然后一次把它们存储到数据库:
Customer cust = new Customer
{
CustomerID = "LAWN",
CompanyName = "Lawn Wranglers",
ContactName = "Mr. Abe Henry",
ContactTitle = "Owner",
Address = "1017 Maple Leaf Way",
City = "Ft. Worth",
Region = "TX",
PostalCode = "",
Country = "USA",
Phone = "(800) MOW-LAWN",
Fax = "(800) MOW-LAWO",
Orders = {
new Order{
CustomerID = "LAWN",
EmployeeID = ,
OrderDate = DateTime.Now,
RequiredDate = DateTime.Now.AddDays(),
ShipVia = ,
Freight = new Decimal(24.66),
ShipName = "Lawn Wranglers",
ShipAddress = "1017 Maple Leaf Way",
ShipCity = "Ft. Worth",
ShipRegion = "TX",
ShipPostalCode = "",
ShipCountry = "USA"
}
}
}; NorthwindEntities db = new NorthwindEntities();
db.Customers.AddObject(cust);
db.SaveChanges();
如果单独创建 Order 和 Customer 对象,就不得不显式的添加 Order:
Customer cust = new Customer
{
CustomerID = "LAWN",
CompanyName = "Lawn Wranglers",
ContactName = "Mr. Abe Henry",
ContactTitle = "Owner",
Address = "1017 Maple Leaf Way",
City = "Ft. Worth",
Region = "TX",
PostalCode = "",
Country = "USA",
Phone = "(800) MOW-LAWN",
Fax = "(800) MOW-LAWO",
}; Order ord = new Order
{
CustomerID = "LAWN",
EmployeeID = ,
OrderDate = DateTime.Now,
RequiredDate = DateTime.Now.AddDays(),
ShipVia = ,
Freight = new Decimal(24.66),
ShipName = "Lawn Wranglers",
ShipAddress = "1017 Maple Leaf Way",
ShipCity = "Ft. Worth",
ShipRegion = "TX",
ShipPostalCode = "",
ShipCountry = "USA"
}; NorthwindEntities db = new NorthwindEntities();
db.Customers.AddObject(cust);
db.Orders.AddObject(ord);
db.SaveChanges();
更新
更新实体类和修改对象的属性一样简单:
NorthwindEntities db = new NorthwindEntities();
Customer cust = (from c in db.Customers
where c.CustomerID == "LAWN"
select c).Single();
cust.ContactName = "John Smith";
cust.Fax = "(800) 123 1234";
db.SaveChanges();
Single():返回序列的唯一元素;如果该序列并非恰好包含一个元素,则会引发异常。
删除
删除也很简单:
NorthwindEntities db = new NorthwindEntities(); IEnumerable<Order_Detail> ods = from o in db.Order_Details
where o.OrderID ==
select o; // 对 LINQ 查询而返回的结果集进行处理
// 要么使用 Single() 取出单条记录
// 要么就迭代集合进行处理
foreach (Order_Detail o in ods)
{
db.Order_Details.DeleteObject(o);
} db.SaveChanges();
注意:Entity Framework 不会删除关联的实体对象,因此调用 SaveChanges()前必须小心地删除所有通过外键约束关联的对象。
管理并发
Entity Framework 默认使用乐观并发模型,也就是说在读取数据后,它不检查是否有人修改了数据库中的数据。调用 SaveChanges()时,所有待更新数据全部被写到数据库中,即使他人已经更新了有冲突的记录时也是如此。
乐观并发会导致痛苦的数据一致性问题。
可以让 Entity Framework 在更新前检查数据库是否由第三方执行了更改,虽然这还是乐观并发,因为实体对象不会锁住数据库的任何对象。但至少它可以在发生问题时给你提醒。
打开实体数据模型,选中字段,在属性中设置“并发模式”为“Fixed”,如下图:

处理并发冲突
为实体对象启用并发冲突检查后,试图更新已经被更新过的数据时,会得到一个 OptimisticConcurrencyException 。为了模拟并发异常,我们使用 Entity Framework 执行更新,然后通过 ExecuteStatementInDb 方法直接执行会造成冲突的 SQL 语句:
protected void Page_Load(object sender, EventArgs e)
{
NorthwindEntities db = new NorthwindEntities();
Customer cust = db.Customers
.Where(c => c.CustomerID == "LAZYK")
.Select(c => c).First(); Response.Write(string.Format("Initial value {0}<br />", cust.ContactName)); // change the record outside of the entity framework
string sql = string.Format(@"update Customers set ContactName = 'Samuel Arthur Sanders'
where CustomerID = 'LAZYK'");
ExecuteStatementInDb(sql); // modify the customer
cust.ContactName = "John Doe"; // save the changes
try
{
db.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
Response.Write("Detected concurrency conflict - giving up<br />");
}
finally
{
sql = string.Format(@"select ContactName from Customers
where CustomerID = 'LAZYK'");
string dbValue = GetStringFromDb(sql);
Response.Write(string.Format("Database value: {0}<br />", dbValue));
Response.Write(string.Format("Cached value: {0}<br />", cust.ContactName));
}
} private void ExecuteStatementInDb(string sql)
{
string conStr = WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
SqlConnection conn = new SqlConnection(conStr);
SqlCommand cmd = new SqlCommand(sql, conn);
try
{
conn.Open();
Response.Write("Executeing Sql statement against database with ADO.NET ...<br />");
cmd.ExecuteNonQuery();
Response.Write("Database updated.<br />");
conn.Close();
}
catch (Exception err)
{
throw new ApplicationException(err.Message);
}
finally
{
conn.Close();
}
} private string GetStringFromDb(string sql)
{
string conStr = WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
SqlConnection conn = new SqlConnection(conStr);
SqlCommand cmd = new SqlCommand(sql, conn);
try
{
conn.Open();
object obj = cmd.ExecuteScalar();
conn.Close();
return obj.ToString();
}
catch (Exception err)
{
throw new ApplicationException(err.Message);
}
finally
{
conn.Close();
}
}

因为在 ContactName 字段上做了并发检查,因此在 Entity Framework 更新时捕获了这个异常,最终更新并没有成功。
不过,我们除了要检查数据的差异,还是想把数据写回数据库,这时可以调用 ObjectContext.Refresh()来解决这一问题,可以在捕获异常时增加这样一条代码:
catch (OptimisticConcurrencyException)
{
Response.Write("Detected concurrency conflict - giving up<br />");
db.Refresh(RefreshMode.StoreWins, cust);
}
Refresh():
- 参数一:RefreshMode 枚举
- 参数二:要刷新的对象
RefreshMode.StoreWins 表示用数据库中的值更新实体对象的值
RefreshMode.ClientWins 表示用实体对象的值更新数据库中的值
让我们回顾一下这里所发生的一切。我们试图向数据库写入在其他某处已经被更新了的数据。Entity Framework 检测到了并发冲突并抛出 OptimisticConcurrencyException 异常,让我们知道发生了问题。我们用数据库里的数据刷新修改了实体对象,它使得我们重新回到一致的状态。
但我们的更新发生了什么?嗯,什么也没有发生。如果我们一定要应用自己的修改的话,就应该使用 RefreshMode.ClientWins 枚举值,并再次调用 SaveChanges():
catch (OptimisticConcurrencyException)
{
Response.Write("Detected concurrency conflict - giving up<br />");
db.Refresh(RefreshMode.ClientWins, cust);
db.SaveChanges();
}
这一回,就好像说“我知道有并发冲突发生了,但我也坚持我的更新”那样。为妥善的处理并发冲突时我们要指出一点:刷新实体对象时可能会有人再次修改数据,也就是说第二次调用 SaveChanges()可能会引发另一个 OptimisticConcurrencyException 异常,为了解决这个问题,我们可以循环尝试应用更新:
// modify the customer
cust.ContactName = "John Doe"; int maxAttempts = 5;
bool recordsUpdated = false; for (int i = 0; i < maxAttempts && !recordsUpdated; i++)
{
try
{
db.SaveChanges();
recordsUpdated = true;
}
catch (Exception)
{
db.Refresh(RefreshMode.ClientWins, cust);
}
}
LINQ(数据库操作增、删、改及并发管理)的更多相关文章
- django单表操作 增 删 改 查
一.实现:增.删.改.查 1.获取所有数据显示在页面上 model.Classes.object.all(),拿到数据后,渲染给前端;前端通过for循环的方式,取出数据. 目的:通过classes(班 ...
- 第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据
第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据 ADO.NET 为什么要学习? 我们要搭建一个平台(Web/Winform ...
- Linq 数据库操作(增删改查)
Linq数据库增删改查 Linq是一种查询语言,集成包含在formwork中,包含在C#语言中,它的作用是降低查询的门槛,提高开发效率,是我们必须掌握的技术之一,下面是我自己对linq数据库操作的方法 ...
- C# ADO.NET (sql语句连接方式)(增,删,改)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- 好用的SQL TVP~~独家赠送[增-删-改-查]的例子
以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础] ...
- MVC EF 增 删 改 查
using System;using System.Collections.Generic;using System.Linq;using System.Web;//using System.Data ...
- iOS sqlite3 的基本使用(增 删 改 查)
iOS sqlite3 的基本使用(增 删 改 查) 这篇博客不会讲述太多sql语言,目的重在实现sqlite3的一些基本操作. 例:增 删 改 查 如果想了解更多的sql语言可以利用强大的互联网. ...
- ADO.NET 增 删 改 查
ADO.NET:(数据访问技术)就是将C#和MSSQL连接起来的一个纽带 可以通过ADO.NET将内存中的临时数据写入到数据库中 也可以将数据库中的数据提取到内存中供程序调用 ADO.NET所有数据访 ...
- iOS FMDB的使用(增,删,改,查,sqlite存取图片)
iOS FMDB的使用(增,删,改,查,sqlite存取图片) 在上一篇博客我对sqlite的基本使用进行了详细介绍... 但是在实际开发中原生使用的频率是很少的... 这篇博客我将会较全面的介绍FM ...
- django ajax增 删 改 查
具于django ajax实现增 删 改 查功能 代码示例: 代码: urls.py from django.conf.urls import url from django.contrib impo ...
随机推荐
- Create a Hadoop Build and Development Environment
Create a Hadoop Build and Development Environment http://vichargrave.com/create-a-hadoop-build-and-d ...
- 小程序中this和that用法
微信小程序中,在wx.request({});方法调用成功或者失败之后,有时候会需要获取页面初始化数据data的情况,这个时候,如果使用,this.data来获取,会出现获取不到的情况,调试页面也会报 ...
- eth
今天说下Centos的eth0:0这个虚拟端口,应为学到ifcofig eth0:0 IP,可以给一个网卡设置俩个IP地址,但是只是临时设置,然而我想永久设置,所以就在网找,最终找到的方法是 可以先复 ...
- Oracle数据库,数字强制显示2位小数
在银行.财务等对数字要求敏感的系统中,数字的显示一般有着严格的要求.今遇到一个需求,如题,要求将数字以两位小数的格式显示,如果没有小数,则强制显示为0.例如:123.4 显示为 123.4012 ...
- idea中查看java类继承图
复习java io,看了书里的这张图,太模糊了,想弄个出来放大看,一开始试了idea发现只能看父类,后来折腾了一会试了其他工具才发现还是idea好用. :) 一.打开type hierachy 光标放 ...
- CSS知识点(一)
一.引入CSS样式(重点掌握) 行内样式 内接样式 外接样式 3.1 链接式 3.1 导入式 css介绍 现在的互联网前端分三层: HTML:超文本标记语言.从语义的角度描述页面结构. CSS:层叠样 ...
- 部署项目到linux中报Spring MVC报异常:org.springframework.web.util.NestedServletException: Request processing failed
@RequestMapping(value = "/security/login", method = RequestMethod.POST) public ModelAndVie ...
- Oracle 12c启动时PDBs的自动打开
Pluggable Database(PDB)为Oracle 12c中的一个重要的新特性, 但启动12c实例时并不会自动打开PDB数据库,这样,在启动实例后必须手动打开PDBs. 1. 实例启动后,手 ...
- Spring控制反转(依赖注入)的最简单说明
1.常规方式实现实例化 1.1已有角色如下: 一个接口Interface,两个接口实现类InstatnceA.InstanceB,一个调用类User 1.2当前实例化InstanceA如下: Inte ...
- web服务器/应用服务器/http服务器/中间件
web服务器:只处理html静态页面不处理动态页面,如apache/nginx/iis等. 应用服务器:能处理html静态页面也能处理动态页面,如tomcat/weblogic/websphere/j ...