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

  • 相关阅读:
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第一题
    fiddler模拟发送post请求
  • 原文地址:https://www.cnblogs.com/wintersun/p/2003706.html
Copyright © 2011-2022 走看看