您的位置:首页 > 数据库

LINQ(数据库操作增、删、改及并发管理)

2014-01-11 20:30 357 查看
本文将演示如何通过EntityFramework数据模型创建、修改、删除数据库记录。

插入

为了在数据库里创建新纪录,需要创建相应实体类的新实例,填充字段,把实体类加入ObjectContext派生类维护的EntityCollection,然后调用SaveChanges()写入新纪录:

Customercust=newCustomer()

{

CustomerID="LAWN",

CompanyName="LawnWranglers",

ContactName="Mr.AbeHenry",

ContactTitle="Owner",

Address="1017MapleLeafWay",

City="Ft.Worth",

Region="TX",

PostalCode="76104",

Country="USA",

Phone="(800)MOW-LAWN",

Fax="(800)MOW-LAWO"

};


NorthwindEntitiesdb=newNorthwindEntities();

db.Customers.AddObject(cust);

db.SaveChanges();


可以多次AddObject()后调用一次SaveChanges()全部写入数据库。

1.创建部分加载的实体类

在之前的示例里,我们调用了Customer实体类的默认构造函数,它创建的实例没有加载任何数据。不过,我们还可以通过在构造函数里指定必须字段的值来减少数据库错误的风险。

每个实体类都有一个名为CreateT的工厂方法,例如,Customer的实体类的工厂方法是CreateCustomer。看下面示例:

Customercust=Customer.CreateCustomer("LAWN","LawnWranglers");

cust.ContactName="Mr.AbeHenry";

cust.ContactTitle="Owner";

cust.Address="1017MapleLeafWay";

cust.City="Ft.Worth";

cust.Region="TX";

cust.PostalCode="76104";

cust.Country="USA";

cust.Phone="(800)MOW-LAWN";

cust.Fax="(800)MOW-LAWO";


NorthwindEntitiesdb=newNorthwindEntities();

db.Customers.AddObject(cust);

db.SaveChanges();


我们倾向于使用默认构造函数,因为可以在一条语句里指定属性的值,但是如果你经常会忘记给必需的字段赋值,那么工厂方法对你就非常有用

2.插入关联的实体

可以用实体类的导航属性创建一组关联的对象,然后一次把它们存储到数据库:

Customercust=newCustomer

{

CustomerID="LAWN",

CompanyName="LawnWranglers",

ContactName="Mr.AbeHenry",

ContactTitle="Owner",

Address="1017MapleLeafWay",

City="Ft.Worth",

Region="TX",

PostalCode="76104",

Country="USA",

Phone="(800)MOW-LAWN",

Fax="(800)MOW-LAWO",

Orders={

newOrder{

CustomerID="LAWN",

EmployeeID=4,

OrderDate=DateTime.Now,

RequiredDate=DateTime.Now.AddDays(7),

ShipVia=3,

Freight=newDecimal(24.66),

ShipName="LawnWranglers",

ShipAddress="1017MapleLeafWay",

ShipCity="Ft.Worth",

ShipRegion="TX",

ShipPostalCode="76104",

ShipCountry="USA"

}

}

};


NorthwindEntitiesdb=newNorthwindEntities();

db.Customers.AddObject(cust);

db.SaveChanges();


如果单独创建Order和Customer对象,就不得不显式的添加Order:

Customercust=newCustomer

{

CustomerID="LAWN",

CompanyName="LawnWranglers",

ContactName="Mr.AbeHenry",

ContactTitle="Owner",

Address="1017MapleLeafWay",

City="Ft.Worth",

Region="TX",

PostalCode="76104",

Country="USA",

Phone="(800)MOW-LAWN",

Fax="(800)MOW-LAWO",

};


Orderord=newOrder

{

CustomerID="LAWN",

EmployeeID=4,

OrderDate=DateTime.Now,

RequiredDate=DateTime.Now.AddDays(7),

ShipVia=3,

Freight=newDecimal(24.66),

ShipName="LawnWranglers",

ShipAddress="1017MapleLeafWay",

ShipCity="Ft.Worth",

ShipRegion="TX",

ShipPostalCode="76104",

ShipCountry="USA"

};


NorthwindEntitiesdb=newNorthwindEntities();

db.Customers.AddObject(cust);

db.Orders.AddObject(ord);

db.SaveChanges();


更新

更新实体类和修改对象的属性一样简单:

NorthwindEntitiesdb=newNorthwindEntities();

Customercust=(fromcindb.Customers

wherec.CustomerID=="LAWN"

selectc).Single();

cust.ContactName="JohnSmith";

cust.Fax="(800)1231234";

db.SaveChanges();


Single():返回序列的唯一元素;如果该序列并非恰好包含一个元素,则会引发异常。

删除

删除也很简单:

NorthwindEntitiesdb=newNorthwindEntities();


IEnumerable<Order_Detail>ods=fromoindb.Order_Details

whereo.OrderID==10248

selecto;


//对LINQ查询而返回的结果集进行处理

//要么使用Single()取出单条记录

//要么就迭代集合进行处理

foreach(Order_Detailoinods)

{

db.Order_Details.DeleteObject(o);

}


db.SaveChanges();


注意:EntityFramework不会删除关联的实体对象,因此调用SaveChanges()前必须小心地删除所有通过外键约束关联的对象

管理并发

EntityFramework默认使用乐观并发模型,也就是说在读取数据后,它不检查是否有人修改了数据库中的数据。调用SaveChanges()时,所有待更新数据全部被写到数据库中,即使他人已经更新了有冲突的记录时也是如此。

乐观并发会导致痛苦的数据一致性问题

可以让EntityFramework在更新前检查数据库是否由第三方执行了更改,虽然这还是乐观并发,因为实体对象不会锁住数据库的任何对象。但至少它可以在发生问题时给你提醒。

打开实体数据模型,选中字段,在属性中设置“并发模式”为“Fixed”,如下图:





处理并发冲突

为实体对象启用并发冲突检查后,试图更新已经被更新过的数据时,会得到一个OptimisticConcurrencyException。为了模拟并发异常,我们使用EntityFramework执行更新,然后通过ExecuteStatementInDb方法直接执行会造成冲突的SQL语句:

protectedvoidPage_Load(objectsender,EventArgse)

{

NorthwindEntitiesdb=newNorthwindEntities();

Customercust=db.Customers

.Where(c=>c.CustomerID=="LAZYK")

.Select(c=>c).First();


Response.Write(string.Format("Initialvalue{0}<br/>",cust.ContactName));


//changetherecordoutsideoftheentityframework

stringsql=string.Format(@"updateCustomerssetContactName='SamuelArthurSanders'

whereCustomerID='LAZYK'");

ExecuteStatementInDb(sql);


//modifythecustomer

cust.ContactName="JohnDoe";


//savethechanges

try

{

db.SaveChanges();

}

catch(OptimisticConcurrencyException)

{

Response.Write("Detectedconcurrencyconflict-givingup<br/>");

}

finally

{

sql=string.Format(@"selectContactNamefromCustomers

whereCustomerID='LAZYK'");

stringdbValue=GetStringFromDb(sql);

Response.Write(string.Format("Databasevalue:{0}<br/>",dbValue));

Response.Write(string.Format("Cachedvalue:{0}<br/>",cust.ContactName));

}

}


privatevoidExecuteStatementInDb(stringsql)

{

stringconStr=WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

SqlConnectionconn=newSqlConnection(conStr);

SqlCommandcmd=newSqlCommand(sql,conn);

try

{

conn.Open();

Response.Write("ExecuteingSqlstatementagainstdatabasewithADO.NET...<br/>");

cmd.ExecuteNonQuery();

Response.Write("Databaseupdated.<br/>");

conn.Close();

}

catch(Exceptionerr)

{

thrownewApplicationException(err.Message);

}

finally

{

conn.Close();

}

}


privatestringGetStringFromDb(stringsql)

{

stringconStr=WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

SqlConnectionconn=newSqlConnection(conStr);

SqlCommandcmd=newSqlCommand(sql,conn);

try

{

conn.Open();

objectobj=cmd.ExecuteScalar();

conn.Close();

returnobj.ToString();

}

catch(Exceptionerr)

{

thrownewApplicationException(err.Message);

}

finally

{

conn.Close();

}

}






因为在ContactName字段上做了并发检查,因此在EntityFramework更新时捕获了这个异常,最终更新并没有成功。

不过,我们除了要检查数据的差异,还是想把数据写回数据库,这时可以调用ObjectContext.Refresh()来解决这一问题,可以在捕获异常时增加这样一条代码:

catch(OptimisticConcurrencyException)

{

Response.Write("Detectedconcurrencyconflict-givingup<br/>");

db.Refresh(RefreshMode.StoreWins,cust);

}


Refresh():

参数一:RefreshMode枚举
参数二:要刷新的对象

RefreshMode.StoreWins表示用数据库中的值更新实体对象的值

RefreshMode.ClientWins表示用实体对象的值更新数据库中的值

让我们回顾一下这里所发生的一切。我们试图向数据库写入在其他某处已经被更新了的数据。EntityFramework检测到了并发冲突并抛出OptimisticConcurrencyException异常,让我们知道发生了问题。我们用数据库里的数据刷新修改了实体对象,它使得我们重新回到一致的状态。

但我们的更新发生了什么?嗯,什么也没有发生。如果我们一定要应用自己的修改的话,就应该使用RefreshMode.ClientWins枚举值,并再次调用SaveChanges():

catch(OptimisticConcurrencyException)

{

Response.Write("Detectedconcurrencyconflict-givingup<br/>");

db.Refresh(RefreshMode.ClientWins,cust);

db.SaveChanges();

}


这一回,就好像说“我知道有并发冲突发生了,但我也坚持我的更新”那样。为妥善的处理并发冲突时我们要指出一点:刷新实体对象时可能会有人再次修改数据,也就是说第二次调用SaveChanges()可能会引发另一个OptimisticConcurrencyException异常,为了解决这个问题,我们可以循环尝试应用更新:

//modifythecustomer

cust.ContactName="JohnDoe";


intmaxAttempts=5;

boolrecordsUpdated=false;


for(inti=0;i<maxAttempts&&!recordsUpdated;i++)

{

try

{

db.SaveChanges();

recordsUpdated=true;

}

catch(Exception)

{

db.Refresh(RefreshMode.ClientWins,cust);

}

}

原文:http://www.cnblogs.com/SkySoot/archive/2012/08/23/2652216.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: