好久沒更新EF這個系列了,現在又重新開始。
這次學習,開放式并發。首先拿出數據庫腳本:
說明一下,這個數據庫腳本是之前的章節中稍作修改的:
USE [SchoolDB] GO /****** Object: Table [dbo].[Student] Script Date: 11/30/2015 21:42:07 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Student]( [StudentID] [INT] NOT NULL, [StudentName] [NVARCHAR](100) NULL, [StandardID] [INT] NULL, [RowVersion] [TIMESTAMP] NOT NULL, CONSTRAINT [PK__Student__32C52A7903317E3D] PRIMARY KEY CLUSTERED ( [StudentID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Student] WITH CHECK ADD CONSTRAINT [FK__Student__Standar__0519C6AF] FOREIGN KEY([StandardID]) REFERENCES [dbo].[Standard] ([StandardID]) GO ALTER TABLE [dbo].[Student] CHECK CONSTRAINT [FK__Student__Standar__0519C6AF] GO
然后,我們在數據模型中更新一下模型EDMx
可以看到Student模型上面,出現了Rowversion字段,我們選中它,右鍵-->屬性,修改并發模式為Fixed。
EF will now include a RowVersion column in the where clause, whenever you do an update operation and if the rowversion value is different than in the where clause then it will throwDbUpdateConcurrencyExection.
下面開始實踐:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Core.Objects; using System.Data.Entity.Infrastructure; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFTutorials { class Program { static void Main(string[] args) { Student stu1 = null; Student stu2 = null; using (var db = new SchoolDBEntities1()) { db.Configuration.ProxyCreationEnabled = false; stu1 = db.Students.Where(s => s.StudentID == 1).FirstOrDefault(); } using (var db = new SchoolDBEntities1()) { db.Configuration.ProxyCreationEnabled = false; stu2 = db.Students.Where(s => s.StudentID == 1).FirstOrDefault(); } stu1.StudentName = "Edit Stuent1"; stu2.StudentName = "Edit Stuent2"; using (var db = new SchoolDBEntities1()) { try { db.Entry(stu1).State = EntityState.Modified; db.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("Optimistic Concurrency exception occured"); } } using (var db = new SchoolDBEntities1()) { try { db.Entry(stu2).State = EntityState.Modified; db.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("Optimistic Concurrency exception occured"); } } } } }
執行完stu1那個查詢之后:
SELECT TOP (1)
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardID] AS [StandardID],
[Extent1].[RowVersion] AS [RowVersion]
FROM [dbo].[Student] AS [Extent1]
WHERE 1 = [Extent1].[StudentID]
執行完,stu1的保存修改之后:
exec sp_executesql N'UPDATE [dbo].[Student]
SET [StudentName] = @0, [StandardID] = NULL
WHERE (([StudentID] = @1) AND ([RowVersion] = @2))
SELECT [RowVersion]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = @1',N'@0 nvarchar(100),@1 int,@2 binary(8)',@0=N'Edit Stuent1',@1=1,@2=0x00000000000007D6
可以肯定的得出,在這里會出錯,也就是并發。
Concurrency in Code-First:
You can create a timestamp property in code-first by usng [Timestamp] attribute. Make sure that the property type is byte[] because timestamp is binary in C#.
[Timestamp]
public byte[] RowVersion { get; set; }
EF includes a property in the where clause, during the update operation, if the property is marked with the Timestamp attribute.
You can resolve concurrency exceptions many ways. Visit msdn for detailed information on how to resolve optimistic concurrency.
Download sample project for the basic tutorials.
今天有點晚了,明天來繼續,怎么解決這個并發。哈哈!!
文章列表