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 ...
随机推荐
- find_first_zero_bit在使用gcc 4.2.4 编译时,需要保护%eax
1.3.100 find_first_zero_bit在使用gcc 4.2.4 编译时,需要保护%eax find_first_zero_bit 修订后: /* * Find-bit routines ...
- vue 基础(一)
一 vue.js的M-V-VM思想 MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式. 1.Model指代的就是vue对象的data属性里面的数据.这里的数 ...
- docker-compose 在线安装升级
参考:https://docs.docker.com/compose/install/ curl -L "https://github.com/docker/compose/releases ...
- hadoop集群添加新节点
0.说明 Hadoop集群已经运行正常,现在新买了一些机子,要加入到集群里面增加新的节点.以下就是增加的过程. 1.配置运行环境 安装与master和其他slave相同的java环境,jdk版本要相同 ...
- 根据list集合某个字段进行排序
import java.util.ArrayList; import java.util.List; class Student { private String name; private doub ...
- Wannafly挑战赛27-A/B
链接:https://www.nowcoder.com/acm/contest/215/A来源:牛客网 题目描述 “White shores, and beyond. A far green coun ...
- python爬虫---requests库的用法
requests是python实现的简单易用的HTTP库,使用起来比urllib简洁很多 因为是第三方库,所以使用前需要cmd安装 pip install requests 安装完成后import一下 ...
- Convex Fence
Convex Fence I have a land consisting of n trees. Since the trees are favorites to cows, I have a bi ...
- sudo执行命令允许教程
1.说明 在Ubuntu中我们可能经常使用sudo执行一些高权限命令:但在CentOS中默认是不允许普通用户sudo的,如同以下情型 [ls@ls bin]$ sudo ifconfig [sudo] ...
- 运维相关 docker