Linq-to-SQL数据的更新、事务、存储过程、函数


  一旦实体对象被加载到内存中,插入新订单的工作就十分 方便,无非是 缔造Order类的实例并将其增加到客户对象的Orders 集中中 。Linq-to-SQL会跟踪数据上下文中的更改,并在调用数据上下文对象的SubmitChanges时将那些更改传回数据库 。下例显示了一个更改数据的过程:

  string id = "ALFKI";Customer c = dataContext.Customers.SingleOrDefault(c => c.CustomerID == id);if(c != null){

  // 批改数据

  c.Address = "123 Flowers Streat);

  //提交更改到数据库中

  dataContext.SubmitChanges();}对象的增加与删除

  数据上下文对象会自动跟踪增加到上下文的对象,并跟踪已被更新、删除或增加的对象 。调用SubmitChanges 步骤会 批示数据上下文类,针对底层的数据库,将挂起的更改转化为更新语句 。

  增加新记录示例:

  Customer customer = new Customer();

  customer.CustomerID = "KOEN2";customer.CompanyName = "…";…dataContext.Customers.InsertOnSubmit(customer);

  dataContext.SubmitChanges();

  删除示例:

  Customer koen2 = dataContext.Customers.SingleOrDefault(c => c.CustomerID == "KOEN2");

  if(koen2 != null){

  dataContext.Customers.DeleteOnSubmit(koen2);

  dataContext.SubmitChanges();}

  在 顺利执行SubmitChanges后,已删除对象在数据上下文中会被标记为Deleted,而不会将其从内部缓存中实际删除 。

  跨表更新

  Linq-to-SQL使我们 可以在数据上下文中对表间关系进行建模,也 支撑跨表更新 。我们要做的只不过从相应的Table对象中将对象移除,其余的工作由SubmitChanges 实现 。

  // 缔造客户Customer mands = new Customer();

  //mands的属性赋值…dataContext.Customers.InsertOnSubmit(mands);

  //增加订单Order order = new Order();

  //为order的属性赋值…//将订单增加到mands的Orders属性中mands.Orders.Add(order);

  //提交更改到数据库中dataContext.SubmitChanges();

  删除上例中增加的客户与订单:

  // 存入客户的订单var orders = from o in dataContext.Orders

  where o.CustomerID == "MANDS"

  select o;//删除订单foreach(var o in orders)

  dataContext.Orders.DeleteOnSubmit(o);

  // 存入客户对象Customer mands = dataContext.Customers.SingleOrDefault(c => c.CustomerID == "MANDS");

  if(mands != null){

  //删除客户并提交更改到数据库中

  dataContext.Customers.DeleteOnSubmit(mands);

  dataContext.SubmitChanges();}

   留神,我们应该首先删除客户订单, 而后再删除该客户 。假如先删除客户,由于客户表与订单表存在表间 束缚,将激发 异样 。

  开放式并发

  以上例为例,我们在删除订单时假如 使用SQL Profile工具跟踪SQL实际执行的语句,可发现它执行的是如下的语句:

  Delete From dbo.CustomersWhere CustomerID = 'MANDS'

  and CompanyName = 'Managed Design'

  and ContactName = 'Dino'

  and ContactTitle is NULL

  and Address = 'Via dei Tigli'

  and City = 'Milan'

  and Region is NULL

  and PostalCode is NULL

  and Country = 'Italy'

  and Phone is NULL

  and Fax is NULL

  这种技术称为"开放式并发",它要求在更新和删除记录前,检测是不是有 其余事务对该记录做了 批改 。" 传统式并发"在更新或删除时,为幸免 摩擦,会对记录加锁 。默许状况下,Linq-to-SQL 使用的是开放式并发 。

  我们 可以将一个参数传给SubmitChanges, 批示它 忽略 摩擦 异样并 接续执行:

  dataContext.SubmitChanges(ConflictMode.ContinueOnConflict);

  默许值为ConflictMode.FailOnFirstConflict.假如 取舍 接续更新,如何获知哪些命令失败呢?

  为此,我们 可以遍历数据上下文的ChangeConflicts 集中:

  try{

  dataContext.SubmitChanges(ConflictMode.ContinueOnConflict);

  }catch(ChangeConflictException e){

  foreach(ObjectChangeConflict occ in dataContext.ChangeConflicts)

  {}}

  ObjectChangeConflict类中定义的属性使我们能了解到底 产生了什么,在哪张表上 产生的,以及 波及了哪个实体对象 。

  更新操作的自定义

  为删除某个客户的全部订单,假如不 使用LINQ,我们可能会这样做:

  Delete From orders Where customerid = 'MANDS'

  Linq-to-SQL提供了一种 步骤, 可以更改实体对象更新操作的实现 。由于Linq-to-SQL构建于分部类之上,我们 惟独增加一个分部 步骤就 可以了 。

  下面是Customer实体的数据上下文类, 可以通过分部 步骤 扩大列表:

  partial void InsertCustomer(Customer instance);

  partial void UpdateCustomer(Customer instance);

  partial void DeleteCustomer(Customer instance);

  这类 步骤的 模式为InsertXxx、UpdateXxx、DeleteXxx,其中Xxx代表数据上下文中实体的名称 。这样,在删除客户记录时,我们 可以这样做:

  partial void DeleteCustomer(Customer instance){

  this.ExecuteCommand("Delete From customers Where customerid={0}", instance.CustomerID);}

   使用此 扩大 步骤后,在删除客户记录时自动删除 有关订单 。

  我们还 可以用更新操作的自定义 特点,用存储过程 接替T-SQL命令来执行数据库操作 。

   使用事务

  通过SubmitChanges提交的全部更新都会在一个事务中进行 。调用该 步骤后,Linq-to-SQL会验证目前调用是不是处于 其余事务的作用 规模,确保消费者 发动的事务没有显式地绑定到数据上下文 。假如没有现有事务,Linq-to-SQL会启动一个当地事务,并 使用该事务执行全部T-SQL命令 。当全部命令都执行 结束后,Linq-to-SQL会提交该事务 。

  我们 可以在自己的代码中 使用TranscationScope对象封装由SubmitChanges 步骤激发的任何数据库操作 。如,通过外部的TranscationScope对象,我们 可以将 其余的非数据库资源引入到事务中, 可以向MSMQ发送 信息,也 可以是更新文件系统 。若SubmitChanges检测到 本身处于某个现有事务的作用域内,它不只会幸免新事务的 缔造,并且还会幸免衔接的关闭 。

  我们还可自行 发动一个事务,将多个SubmitChanges的命令与该事务关联 。为此,我们可 使用数据上下文对象的Transaction属性 。提交或回滚 彻底取决于开发者 。假如事务的衔接字符串与数据上下文所 使用的不匹配,则会有 异样抛出 。

   使用存储过程

  我们 可以在分部 步骤中 使用ExecuteCommand 步骤执行存储过程 。示例:

  partial void DeleteCustomer(Customer instance){

  this.ExecuteCommand("exec delete_customer {0}", instance.CustomerID);}

  此外,我们 可以在VS2008的O/R设计器将存储过程增加到数据上下文中,就可将存储过程当成数据上下文的 步骤来调用 。

   假如我们已将名为CustOrderHist的存储过程增加到数据上下文中,调用 步骤如下:

  var orders = dataContext.CustOrderHist(customerID);

  我们可 使用var 要害字对 后果类型进行判断 。若存储过程返回多个值或不同类型的值,数据上下文中该存储过程的封装器会返回IMultipleResults类型,在这种状况下,我们可 使用GetResult<T>来 拜访给定的 后果 。其中T用于指定特定 后果的类型 。

   使用消费者定义的函数

  与存储过程 类似,消费者在数据库中的自定义函数也可附加到数据上下文中,并在页面中以 步骤的 模式调用 。