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 ...
随机推荐
- GreenDao使用解析
GreenDao是一个轻量级的数据库框架,相比Xutils 等他的速度和效率会更快更好 这里展示GreenDao 的使用方法 ①建立 compile 'org.greenrobot:greendao: ...
- test example
#coding=utf-8 import os import caffe import numpy as np root='/home/xxx/caffe/' #根目录 deploy=root + ' ...
- python安装pandas和lxml
一.安装python 二.安装pip 三.安装mysql-connector(window版):下载mysql-connector-python-2.1.3,解压后进入目录,命令安装:pip inst ...
- 树上第k大联通块
题意:求树上第k大联通块 n,k<=1e5 考虑转化为k短路的形式. 也就是要建出一张图是的这条图上每一条S到T的路径都能代表一个联通块. 点分治建图 递归下去,假定每个子树的所有联通块中都可以 ...
- World Tour CodeForces - 667D (bfs最短路)
大意: 有向图, 求找4个不同的点ABCD, 使得d(A,B)+d(D,C)+d(C,A)最大
- 廖雪峰网站:学习python函数—定义函数(二)
def my_abs(x): if x >= 0: return x else: return -x print(my_abs(-99)) # 空函数 def nop(): pass # 参数检 ...
- git merge和git rebase的区别
git merge是用来合并两个分支的.# 将b分支合并到当前分支git merge b git cherry-pick可以选择某一个分支中的一个或几个commit(s)来进行操作.例如,假设我 们有 ...
- ORACLE-016:ora-01720 授权选项对于'xxxx'不存在
报错的情形如下, A用户:视图V_A B用户:视图V_B,并且用到了V_A C用户:需要用V_B, 授权过程, A用户下: grant select on V_A to B B用户下: grant s ...
- 学习Spring Security OAuth认证(一)-授权码模式
一.环境 spring boot+spring security+idea+maven+mybatis 主要是spring security 二.依赖 <dependency> <g ...
- [CodeForces - 447D] D - DZY Loves Modification
D - DZY Loves Modification As we know, DZY loves playing games. One day DZY decided to play with a n ...