WCF如何正确调用LINQ TO SQL更新操作

WCF如何正确调用LINQ TO SQL--更新操作

     上一篇讲到WCF如何正确调用LINQ TO SQL,只涉及到了新增记录的操作。到于为什么要把更新操作分开来讲呢?因为更新确实有点麻烦,相对于新增操作来说,稍微有点难。
     还是使用上一篇的项目,没有源码的兄弟可以到这里下载上一篇的项目:https://files.cnblogs.com/viter/WCF.rar
首先我们新建一个WinForm窗体UpdateForm,在客户端界面添加一个DataGridView,用来存储从服务读取到的数据,命名为:dgvPurchaseOrder,并在代码中设置自动生成列为False。其实用BindingSource更快,呵呵。
     那好,还是使用BindingSource,不过这个BindingSource是自定义的,因为用来做数据显示控制没有比它更称职的了。


        private BindingSource bdsOrder = new BindingSource();
        
private
 PurchaseOrderHeader purchaseOrderHeader;

        
public
 UpdateOrderForm()
        {
            InitializeComponent();
            bdsOrder.CurrentChanged 
+= new
 EventHandler(bdsOrder_CurrentChanged);
        }

为这个BindingSource定义一个事件,就是BindingSource的CurrentChanged事件。
这个事件里的代码如下,很简单。

CurrentChanged


在界面加载的事件从服务器调取数据
  

client

     现在我们的数据出来了,好,我们修改一下订单总额,提交到服务器。
我们将出错信息写到控制台,好好欣赏一下吧,呵呵。好像是真的一样。


     为什么会出现这个错误?我们还是来调试一下,看得更仔细点。

     

     看,好像告诉我们,你要修改的数据已经存在,不能添加。想想有点不妥啊!非常不妥,我不是要添加数据,是要修改数据,为什么会提示“无法附加已经存在的实体”?好,注意看,MS用词还是很恰当的,看这一句:“无法附加已经存在的实体”,注意,是实体!!!那意思是我们的操作没有任何的问题,是实体出了问题,再想一下,我们的实体是通过什么方式来取得的呢?你肯定在电光火石之间想到了,是DataContext,对,是数据上下文,如果你对单张表进行操作,我敢保证你一辈子也不会遇上这个异常,真的不会。好了,现在我们来看下数据库关系图

     这两张表是有关联的,不是独立的表。可能这样还是有点看不明白,不要紧,再看一下生成的DBMl文件。
PurchaseOrderHeader类里面有一个属性


private EntitySet<PurchaseOrderDetail> _PurchaseOrderDetail;
[Association(Name
="PurchaseOrderHeader_PurchaseOrderDetail", Storage="_PurchaseOrderDetail", OtherKey="PurchaseOrderHeaderId"
)]
  [DataMember(Order
=6, EmitDefaultValue=false
)]
  
public EntitySet<PurchaseOrderDetail>
 PurchaseOrderDetail
  {
   
get

   {
    
if ((this.serializing 
       
&& (this._PurchaseOrderDetail.HasLoadedOrAssignedValues == false
)))
    {
     
return null
;
    }
    
return this
._PurchaseOrderDetail;
   }
   
set

   {
    
this._PurchaseOrderDetail.Assign(value);
   }
  }

相对的,PurchaseOrderDetail类里面也有一个对应的属性,用来关联


private EntityRef<PurchaseOrderHeader> _PurchaseOrderHeader;
[Association(Name
="PurchaseOrderHeader_PurchaseOrderDetail", Storage="_PurchaseOrderHeader", ThisKey="PurchaseOrderHeaderId", IsForeignKey=true
)]
  
public
 PurchaseOrderHeader PurchaseOrderHeader
  {
   
get

   {
    
return this._PurchaseOrderHeader.Entity;
   }
   
set

   {
    PurchaseOrderHeader previousValue 
= this._PurchaseOrderHeader.Entity;
    
if (((previousValue !=
 value) 
       
|| (this._PurchaseOrderHeader.HasLoadedOrAssignedValue == false
)))
    {
     
this
.SendPropertyChanging();
     
if ((previousValue != null
))
     {
      
this._PurchaseOrderHeader.Entity = null
;
      previousValue.PurchaseOrderDetail.Remove(
this
);
     }
     
this._PurchaseOrderHeader.Entity =
 value;
     
if ((value != null
))
     {
      value.PurchaseOrderDetail.Add(
this
);
      
this._PurchaseOrderHeaderId =
 value.PurchaseOrderHeaderId;
     }
     
else

     {
      
this._PurchaseOrderHeaderId = default(int);
     }
     
this.SendPropertyChanged("PurchaseOrderHeader"
);
    }
   }
  }

可以看到,这两个属性是标记数据库两张表的一对多的关系。
那么我们分析一下,在我们从数据库检索数据的时候,这个关系是否存在?答案是肯定的!
不好意思,这个图切不下来,各位可以在这里设置断点查看


     通过这里可以看到,关系是存在的,只是由于Linq的延迟加载的特性,数据并没有读取出来而已。
那么我们就要问了,在查询的时候会有关系,那么向数据库添加数据的时候呢?看一下下面的表格,已经有很好的答案


     好了,既然要关系,我们就加一个试试,在这之前你需要引用System.Data.Linq.dll,并引用System.Data.Linq命名空间。
加关系很简单,在原来的Update方法里面加一个判断就可以了,如果是修改或删除的操作,那么我们就给它加上关系。
1~~*和*~~1的关系设置不一样,注意代码里面的设置。


#region 添加订单头
                    
//设置行最后修改时间
                 foreach (var item in purchaseOrderHeaderList)
                 {
                     
//如果是新增或者是删除操作,则设置关系

                     if (item.CurrentStatus == EntityStatus.Update || item.CurrentStatus == EntityStatus.Delete)
                     {
                         
//一对多的关系

                         item.PurchaseOrderDetail = default(EntitySet<PurchaseOrderDetail>);
                     }
                     item.ModifiedDate 
=
 DateTime.Now;
                 }
                 result 
= Common<PurchaseOrderHeader, PurchaseOrderDetail>.GenericUpdate(purchaseOrderHeaderList, "PurchaseOrderDetail"
, PurchaseTable.PurchaseOrderDetail);
                    
#endregion


                 
#region //添加订单细目
                 
foreach (var headeritem in purchaseOrderHeaderList)
                 {
                     
if (headeritem.PurchaseOrderDetails != null
)
                     {
                         
foreach (var detailitem in
 headeritem.PurchaseOrderDetails)
                         {
                             
//如果是新增或者是删除操作,则设置关系

                             if (detailitem.CurrentStatus == EntityStatus.Update || detailitem.CurrentStatus == EntityStatus.Delete)
                             {
                                 
//多对一的关系

                                 detailitem.PurchaseOrderHeader = new PurchaseOrderHeader() { PurchaseOrderHeaderId = detailitem.PurchaseOrderHeaderId };
                             }
                             
//订单头添加完成后,将会产生一个新的PurchaseOrderHeaderId

                             detailitem.PurchaseOrderHeaderId = headeritem.PurchaseOrderHeaderId;
                             
//设置行最后修改时间

                             detailitem.ModifiedDate = DateTime.Now;
                             detailList.Add(detailitem);
                         }
                     }
                 }
                 
#endregion

                 


好,我们现在来修改订单编号为1的记录,将订单总额改为5000.

成功!


 

欢迎转载,但请注明出处--梁规晓博客(http://www.cnblogs.com/viter/)!
下一篇将介绍“如何将WCF和WF无缝的结合”。谢谢大家的关注!

点击下面下载服务端和客户端源代码.

https://files.cnblogs.com/viter/WCF2.rar

说得不对的地方,欢迎拍砖!

原文地址:https://www.cnblogs.com/dudu837/p/1549838.html