zoukankan      html  css  js  c++  java
  • EntityFamework 4.0 中的并发处理(一)

           Entity Framework 4.0 在默认时并不处理并发的情况,也就是出现并发忽略它们。但EF支持处理并发的情况,有两种方法,一种是在存储过程中自行处理。另一种是EF的MODEL上增加一个TimeStamp,EF支持这个TimeStamp来处理并发。看下面EF的模型EDM中SSDL节:

       1:          <EntityType Name="Categories2">
       2:            <Key>
       3:              <PropertyRef Name="CategoryID" />
       4:            </Key>
       5:            <Property Name="CategoryID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
       6:            <Property Name="CategoryName" Type="nvarchar" MaxLength="15" />
       7:            <Property Name="Description" Type="ntext" />
       8:            <Property Name="Picture" Type="image" />
       9:            <Property Name="RowVersion" Type="timestamp" Nullable="false" StoreGeneratedPattern="Computed" />
      10:          </EntityType>

    CSDL节:

       1:  <EntityType Name="Categories2">
       2:            <Key>
       3:              <PropertyRef Name="CategoryID" />
       4:            </Key>
       5:            <Property Type="Int32" Name="CategoryID" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
       6:            <Property Type="String" Name="CategoryName" MaxLength="15" FixedLength="false" Unicode="true" />
       7:            <Property Type="String" Name="Description" MaxLength="Max" FixedLength="false" Unicode="true" />
       8:            <Property Type="Binary" Name="Picture" MaxLength="Max" FixedLength="false" />
       9:            <Property Type="Binary" Name="RowVersion" Nullable="false" MaxLength="8" FixedLength="true" annotation:StoreGeneratedPattern="Computed" ConcurrencyMode="Fixed" />
      10:          </EntityType>

    注意第9行,我们新增加一个列RowVersion. 它的ConcurrencyMode等Fixed,这个是关键之处。这里我们使用POCO:

       1:      [DataContract] 
       2:      public partial class Categories2
       3:      {
       5:          [DataMember]
       6:          public virtual int CategoryID
       7:          {
       8:              get;
       9:              set;
      10:          }
      11:          [DataMember]
      12:          public virtual string CategoryName
      13:          {
      14:              get;
      15:              set;
      16:          }
      17:          [DataMember]
      18:          public virtual string Description
      19:          {
      20:              get;
      21:              set;
      22:          }
      23:          [DataMember]
      24:          public virtual byte[] Picture
      25:          {
      26:              get;
      27:              set;
      28:          }
      29:          [DataMember]
      30:          public virtual byte[] RowVersion
      31:          {
      32:              get;
      33:              set;
      34:          }

    注意,那个attribute不是必须的。接下来看到主要代码:

       1:             using (var context = new DBEntities())
       2:              {
       3:                  //Add new categroy
       4:                  Categories2 newcategroy = new Categories2() { CategoryName = "testname" };
       5:                  context.Categories2.AddObject(newcategroy);
       6:                  context.SaveChanges();
       7:                  //Get it
       8:                  var categoriesfromdb = context.Categories2.Where(c => c.CategoryID == newcategroy.CategoryID).First();
       9:                  Console.WriteLine("Just insert category Id: {0}", categoriesfromdb.CategoryID);
      10:                  
      11:                  //使用SQL执行一个Update模拟并发的情况
      12:                  context.ExecuteStoreCommand(@"update Categories2 set CategoryName='456' where CategoryID = @p0"
      13:                      , categoriesfromdb.CategoryID );
      14:              
      15:                  categoriesfromdb.CategoryName = "testname333";
      16:   
      17:                  try
      18:                  {
      19:                      context.SaveChanges();
      20:                      Console.WriteLine("No concurrency exception.");
      21:                  }
      22:                  catch (OptimisticConcurrencyException)
      23:                  {
      24:                       ///出现并发冲突的处理
      25:                      Console.WriteLine(" concurrency exception happend");
      26:                      //testname333
      27:                      //implement last record wins strategy
      28:                      context.Refresh(System.Data.Objects.RefreshMode.ClientWins, categoriesfromdb);
      29:                      //456
      30:                      //context.Refresh(System.Data.Objects.RefreshMode.StoreWins, categoriesfromdb);
      31:   
      32:                      Console.WriteLine("categoriesfromdb.CategoryName: {0} ", categoriesfromdb.CategoryName);
      33:                      Console.WriteLine("OptimisticConcurrencyException handled and changes saved");
      34:   
      35:                      context.SaveChanges();  
      36:                  }
      37:   
      38:                  //Clear
      39:                  context.DeleteObject(newcategroy);
      40:                  context.SaveChanges();
      41:              }

    你可以把上面的代码放到一个UnitTest中, 先增加一个Entity,然后从DB查询出,然后用T-SQL语句修改它,  后面接着又修它的属性。运行时我们将Catch到OptimisticConcurrencyException

    输出:

    Just insert category Id: 58
    concurrency exception happend
    categoriesfromdb.CategoryName: 456
    OptimisticConcurrencyException handled and changes saved

    1 passed, 0 failed, 0 skipped, took 0.83 seconds (Ad hoc).

    EF中有两种处理模式强制用户数据到服务器(ClientWins)和用服务器数据刷新用户数据(StoreWins),上面代码使用Context来RefreshModel.ClientWins,最后Name属性是testname333,实现了并发中“最后一个赢”的效果。相反,使用StoreWins策略那个属性的值将是456。 最后清理刚才测试的对象。

    这是上面通过Command运行的Update T-SQL:

    exec sp_executesql N'update Categories2 set CategoryName=''456'' where CategoryID = @p0',N'@p0 int',@p0=60

    我们再看来EF是怎么实现的, SaveChange时生成的T-SQL是:

       1:  exec sp_executesql N'update [dbo].[Categories2]
       2:  set [CategoryName] = @0
       3:  where (([CategoryID] = @1) and ([RowVersion] = @2))
       4:  select [RowVersion]
       5:  from [dbo].[Categories2]
       6:  where @@ROWCOUNT > 0 and [CategoryID] = @1',N'@0 nvarchar(15),@1 int,@2 binary(8)',@0=N'testname333',@1=60,@2=0x0000000000008521

    注意TimeStamp做为了where查询的子句,这样保证了这条数据的被更新。 我们还可以使用SQL SERVER 2008 中 rowversion 类型 来做为这个列的类型。

    希望这篇POST对您开发有帮助。


    作者:Petter Liu
    出处:http://www.cnblogs.com/wintersun/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    该文章也同时发布在我的独立博客中-Petter Liu Blog

  • 相关阅读:
    Linux下设置 Tomcat JDK MySQL运用平台
    引见在Linux把持细碎下装置Tomcat的要领
    在linux下的freetds装置体式款式
    介绍两款超级小的linux,可以安排在u盘里玩
    在Debian环境下架设PPPoE效劳器2
    GRUB2 指导按次的开展目标
    Linux下设置配备布置服从完美的Web效力器
    Ubuntu Linux体系创设FTP办事器装备步调
    高效运用Linux的七个好习气2
    Ubuntu Linux 8.04零碎JAVA环境设置装备陈设体式格式
  • 原文地址:https://www.cnblogs.com/wintersun/p/2003706.html
Copyright © 2011-2022 走看看