پرامید کنکرنسی کنٹرول متعدد رسائیوں (ایس کیو ایل سرور) کے ساتھ آخری جیت کی تازہ کاریوں کی وجہ سے ڈیٹا کے نقصان کو روکتا ہے

جب صفحے کی تازہ کاری :
صفحہ تخلیق تاریخ :

آپریٹنگ ماحول

Visual Studio
  • Visual Studio 2022
.جال
  • .NET 8
Entity Framework Core
  • Entity Framework Core 8.0
SQL Server
  • SQL Server 2022

* مندرجہ بالا ایک تصدیقی ماحول ہے، لیکن یہ دوسرے ورژن کے ساتھ کام کر سکتا ہے.

بغیر کنٹرول کے تازہ کاری جیتنے کے بارے میں

ایک ویب ایپلی کیشن یا کلائنٹ سرور ایپلی کیشن میں ، متعدد لوگ ایک ہی ڈیٹا بیس سے ڈیٹا تک رسائی اور اپ ڈیٹ کرسکتے ہیں۔ اگر خاص طور پر کچھ نہیں کیا جاتا ہے تو ، جس شخص نے اسے بعد میں اپ ڈیٹ کیا اس کا ڈیٹا ڈیٹا بیس میں تازہ ترین کے طور پر ظاہر ہوگا۔

عام طور پر ، کوئی خاص مسئلہ نہیں ہے کہ بعد میں اپ ڈیٹ کرنے والے شخص کا ڈیٹا تازہ ترین کے طور پر ظاہر ہوتا ہے۔ مسائل پیدا ہوسکتے ہیں جب متعدد لوگ ایک ہی وقت میں ایک ہی ڈیٹا تک رسائی حاصل کرنے اور اپ ڈیٹ کرنے کی کوشش کرتے ہیں۔

مثال کے طور پر ، فرض کریں کہ آپ کے پاس مندرجہ ذیل کتاب کا ڈیٹا ہے۔

پیرامیٹر نام کی قدر
کتاب کا نام ڈیٹا بیس کی کتابیں
قیمت 1000

اگر دو افراد ایک ہی وقت میں اس ڈیٹا میں ترمیم کرنے کے لئے اسکرین کھولتے ہیں تو ، مندرجہ بالا قیمت ظاہر ہوگی۔ محترمہ اے اس کتاب کی قیمت میں 500 ین کا اضافہ کرنے کی کوشش کر رہی ہیں۔ مسٹر / مس بی کو بعد میں ہدایت کی گئی ہے کہ وہ اس کتاب کی قیمت میں مزید 300 ین کا اضافہ کریں۔

اگر وہ دونوں ایک ہی وقت کے بجائے الگ الگ قیمت میں اضافہ کرتے ہیں تو کتاب کی قیمت 1800 ین ہوگی۔ اگر آپ اسی وقت اس تک رسائی حاصل کرتے ہیں تو ، یہ بالترتیب 1500 ین اور 1300 ین کے طور پر رجسٹرڈ ہوگا ، لہذا یہ 1800 ین نہیں ہوگا چاہے کوئی بھی رجسٹر ہو۔

یہاں مسئلہ یہ ہے کہ جس شخص نے بعد میں اپ ڈیٹ کیا وہ پہلے اپ ڈیٹ کی گئی معلومات کو جانے بغیر اسے اپ ڈیٹ کرسکتا ہے۔

پرامید امید

مذکورہ بالا مسئلے کو اس بار "پرامید کنکرنسی کنٹرول" انجام دے کر حل کیا جاسکتا ہے۔ آسانی سے وضاحت کرنے کے لئے ، "اگر آپ ایک ہی وقت میں ڈیٹا میں ترمیم کرنے کی کوشش کرتے ہیں تو پہلے جیتنا کس طرح کا کنٹرول ہے"۔ جو لوگ بعد میں تجدید کرنے کی کوشش کریں گے انہیں اپ ڈیٹ کے وقت ایک نقص موصول ہوگا اور وہ اندراج نہیں کرسکیں گے۔

آپ سوچ سکتے ہیں کہ آپ اس کے ساتھ نیا ڈیٹا رجسٹر نہیں کرسکتے ہیں ، لیکن یہ صرف "جب آپ اسے ایک ہی وقت میں تبدیل کرنے کی کوشش کرتے ہیں"۔ دو افراد کے لئے مکمل طور پر مختلف اوقات میں ترمیم کرنا ممکن ہے۔ یقینا ، اس صورت میں ، آخری اپ ڈیٹ شدہ شخص کا ڈیٹا تازہ ترین ہوگا۔

خاص طور پر ، "ڈیٹا کا ورژن رکھنے" سے کس قسم کا پروسیسنگ کنٹرول حاصل کیا جاسکتا ہے۔ مثال کے طور پر ، مندرجہ بالا مثال میں ، آپ کے پاس مندرجہ ذیل ڈیٹا ہوگا۔

پیرامیٹر نام کی قدر
کتاب کا نام ڈیٹا بیس کی کتابیں
قیمت 1000
ورژن 1

ہر ریکارڈ اپ ڈیٹ کے لئے ورژن میں 1 کا اضافہ کیا گیا ہے۔ مثال کے طور پر ، اگر مسٹر / مس اے قیمت 1500 ین مقرر کرتا ہے تو ، ورژن 2 ہوگا۔ اس وقت ، شرط یہ ہے کہ اپ ڈیٹ کیا جاسکتا ہے کہ اپ ڈیٹ سے پہلے کا ورژن ڈیٹا بیس پر موجود ورژن جیسا ہی ہو۔ جب مسٹر / محترم اسے اپ ڈیٹ کرتے ہیں تو ، ڈیٹا بیس پر ورژن 1 ہوتا ہے ، اور اس وقت ترمیم شدہ اصل ڈیٹا کا ورژن 1 ہے ، لہذا اسے اپ ڈیٹ کیا جاسکتا ہے۔

اس وضاحت کی بنیاد پر ، ایک ایسی صورتحال کا اندازہ لگائیں جہاں مسٹر / مس اے اور مسٹر / مس بی ایک ہی ڈیٹا میں ترمیم کریں۔ جب مسٹر / مس نے پہلی بار قیمت 1500 ین مقرر کی اور ڈیٹا بیس کو اپ ڈیٹ کرنے کی کوشش کی ، تو ورژن وہی تھا ، لہذا اسے اپ ڈیٹ کیا جاسکتا ہے۔ اس صورت میں ، ڈیٹا بیس پر ورژن 2 ہوگا۔ مسٹر / مس بی 1000 ین کے اعداد و شمار میں ترمیم کرنے اور اسے 1300 ین کے طور پر ڈیٹا بیس میں اپ ڈیٹ کرنے کی کوشش کرتا ہے۔ اپ ڈیٹ ناکام ہوجاتا ہے کیونکہ ہاتھ میں موجود ورژن 1 ہے ، لیکن ڈیٹا بیس پر ورژن پہلے ہی 2 ہے۔ اس طرح پرامید کنکرنسی کام کرتی ہے۔

انٹیٹی فریم ورک کور میں اس "پرامید کنکرنسی" کو باکس سے باہر شامل کیا گیا ہے ، جس سے اس پر عمل درآمد کرنا نسبتا آسان ہوجاتا ہے۔

ویسے ، "پرامید کنکرنسی" کو "پرامید لاک" یا "پرامید لاک" بھی کہا جاتا ہے ، اور بعض اوقات اس کی جانچ پڑتال کی جاتی ہے اور اس کے بارے میں اس نام سے بات کی جاتی ہے۔ یہ ایک لاکنگ طریقہ ہے کہ ڈیٹا کو اپ ڈیٹ نہیں کیا جاسکتا ہے ، لیکن ڈیٹا کو پڑھا جاسکتا ہے۔ "پرامید لاک" کے علاوہ ایک اور لاکنگ طریقہ کے طور پر "مایوس کن لاک" نامی ایک کنٹرول بھی ہے۔ یہ ایک ایسا طریقہ ہے جو ڈیٹا لوڈنگ کو لاک کرتا ہے جب پہلا شخص ڈیٹا پڑھتا ہے اور ایڈیٹنگ آپریشنز کی بھی اجازت نہیں دیتا ہے۔ یہ اس مسئلے کو حل کرسکتا ہے کہ ڈیٹا کو تبدیل کرنے کے باوجود اپ ڈیٹ نہیں کیا جاسکتا ہے ، لیکن جب کوئی ڈیٹا میں ترمیم کررہا ہوتا ہے تو ، دوسرے لوگ ڈیٹا ایڈیٹنگ اسکرین نہیں کھول سکتے ہیں ، اور اگر ان لاک ناکام ہوجاتا ہے تو ، ڈیٹا ہمیشہ کے لئے لاک ہوجائے گا۔ دونوں کے فوائد اور نقصانات ہیں ، لہذا یہ آپریشن پر منحصر ہے کہ کس کو اپنانا ہے۔

ایک ڈیٹا بیس بنانا

اس مضمون میں ، میں وضاحت کروں گا کہ پہلے ایس کیو ایل سرور کے لئے ڈیٹا بیس کیسے بنائیں اور پھر خود بخود کوڈ تیار کریں۔ اگر آپ اسے کوڈ فرسٹ طریقے سے نافذ کرنا چاہتے ہیں تو، براہ کرم اس بار خود بخود تیار کردہ کوڈ کا حوالہ دیں اور اسے ریورس پروسیجر میں لاگو کریں۔

ایک ڈیٹا بیس بنانا

آپ اسے ایس کیو ایل میں بھی بنا سکتے ہیں ، لیکن اسے جی یو آئی کے ساتھ بنانا آسان ہے ، لہذا میں اس بار اسے جی یو آئی کے ساتھ بنا رہا ہوں۔ ڈیٹا بیس کے نام کے علاوہ ، یہ پہلے سے طے شدہ طور پر بنایا گیا ہے۔

ایک جدول بنائیں

اسے درج ذیل SQL کے ساتھ بنائیں:

USE [TestDatabase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Book](
	[ID] [int] NOT NULL,
	[Name] [nvarchar](100) NOT NULL,
	[Price] [money] NOT NULL,
	[RowVersion] [timestamp] NOT NULL,
 CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

آپ کو زیادہ تر پیرامیٹرز کے بارے میں فکر کرنے کی ضرورت نہیں ہے کیونکہ وہ صرف ڈیٹا اپ ڈیٹس کے لئے ہیں۔ اس بار دلچسپی کا پیرامیٹر وہ کالم ہے RowVersion جو بیان کرتا ہے۔ یہ ریکارڈ ورژن ہے. قسم کے طور پر وضاحت کرکے timestamp ، ہر بار جب ریکارڈ کو اپ ڈیٹ کیا جاتا ہے تو ورژن خود بخود بڑھ جاتا ہے۔ نیز ، چونکہ یہ ورژن فی ٹیبل کی بنیاد پر منظم کیا جاتا ہے ، لہذا بنیادی طور پر اسی ورژن کا کوئی ریکارڈ نہیں ہے جب تک کہ آپ اسے دستی طور پر سیٹ نہ کریں۔

ایک ریکارڈ شامل کریں

آپ اسے درج ذیل ایس کیو ایل کے ساتھ شامل کرسکتے ہیں:

begin transaction;
insert into Book ([ID],[Name],[Price]) values (1,'C#の本','1000.00');
insert into Book ([ID],[Name],[Price]) values (2,'VB.NETの本','1500.00');
insert into Book ([ID],[Name],[Price]) values (3,'SQL Serverの本','2000.00');
commit;

RowVersion آپ کو کالم سیٹ کرنے کی ضرورت نہیں ہے کیونکہ وہ خود بخود سیٹ ہوتے ہیں۔

ایک پروجیکٹ بنائیں اور خود بخود کوڈ پیدا کریں

اس بار ، ہم کنسول ایپلی کیشن کے ساتھ آپریشن چیک کریں گے۔ ایک پروجیکٹ بنانے اور خود بخود کوڈ پیدا کرنے کے اقدامات مندرجہ ذیل نکات میں بیان کیے گئے ہیں ، لہذا میں ان میں یہاں نہیں جاؤں گا۔

تیار کردہ کوڈ مندرجہ ذیل ہے:

TestDatabaseDbContext.cs

using Microsoft.EntityFrameworkCore;

namespace ConcurrencySqlServer.Models.Database;

public partial class TestDatabaseDbContext : DbContext
{
  public TestDatabaseDbContext() { }

  public TestDatabaseDbContext(DbContextOptions<TestDatabaseDbContext> options) : base(options) { }

  public virtual DbSet<Book> Book { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
    => optionsBuilder.UseSqlServer("Data Source=<サーバー名>;Database=<データベース名>;user id=<ユーザー名>;password=<パスワード>;TrustServerCertificate=true");

  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Book>(entity =>
    {
      entity.Property(e => e.ID).ValueGeneratedNever();
      entity.Property(e => e.RowVersion)
        .IsRowVersion()
        .IsConcurrencyToken();
    });

    OnModelCreatingPartial(modelBuilder);
  }

  partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

Book.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ConcurrencySqlServer.Models.Database;

public partial class Book
{
  [Key]
  public int ID { get; set; }

  [StringLength(100)]
  public string Name { get; set; } = null!;

  [Column(TypeName = "money")]
  public decimal Price { get; set; }

  public byte[] RowVersion { get; set; } = null!;
}

پرامید کنکرنسی کنٹرول کے آپریشن کی جانچ پڑتال

چونکہ ہم اس بار اسے ایک ایپلی کیشن میں چلا رہے ہیں ، لہذا ہم ایک ہی وقت میں اس تک سختی سے رسائی حاصل نہیں کررہے ہیں ، لیکن ہم اسے اس کے قریب ایک فارم میں لاگو کرنا چاہتے ہیں۔

جیسا کہ شروع میں مثال میں ہے ، ڈیٹا کے دو ٹکڑے حاصل کیے جاتے ہیں ، اور جب ہر ایک کو پہلے ڈیٹا کی بنیاد پر اپ ڈیٹ کیا جاتا ہے تو ، چیک کریں کہ آیا مؤخر الذکر اپڈیٹر کو غلطی ملے گی یا نہیں۔

Program.cs

using ConcurrencySqlServer.Models.Database;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;

Console.WriteLine("Hello, World!");

// 2人が別々にデータベースにアクセスする想定で2つのデータベースコンテキストを作成
Console.WriteLine("データベースコンテキストを作成します。");
using var dbContextA = new TestDatabaseDbContext();
using var dbContextB = new TestDatabaseDbContext();
Console.WriteLine("データベースコンテキストを作成しました。");
Console.WriteLine("");

// それぞれがデータを編集しようと読み込む
Console.WriteLine("ID:1 の Book を読み込みます。");
var bookA = dbContextA.Book.First(x => x.ID == 1);
var bookB = dbContextB.Book.First(x => x.ID == 1);
Console.WriteLine("ID:1 の Book を読み込みました。");
Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");
Console.WriteLine("");


// A の人が最初にデータベースに更新する
bookA.Price += 500;
UpdateToDatabase(dbContextA, "A");

Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");
Console.WriteLine("");

// そのあと B の人が最初にデータベースに更新する
bookB.Price += 300;
UpdateToDatabase(dbContextB, "B");

Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");
Console.WriteLine("");

Console.WriteLine("処理を終了します。");


// データベースに更新するメソッド
void UpdateToDatabase(TestDatabaseDbContext dbContext, string updateUser)
{
  try
  {
    Console.WriteLine($"{updateUser} のデータベースコンテキストを変更保存します。");
    dbContext.SaveChanges();
    Console.WriteLine($"{updateUser} のデータベースコンテキストを変更保存しました。");
  }
  catch (DbUpdateConcurrencyException ex)
  {
    Console.WriteLine($"{updateUser} の更新でエラーが発生しました。");
    Console.WriteLine(ex.Message);
  }
}

یہ ایک لمبی کہانی ہے ، لیکن اس میں سے زیادہ تر کنسول پر لکھا گیا ہے۔

پھانسی کا نتیجہ درج ذیل ہے۔

Hello, World!
データベースコンテキストを作成します。
データベースコンテキストを作成しました。

ID:1 の Book を読み込みます。
ID:1 の Book を読み込みました。
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}

A のデータベースコンテキストを変更保存します。
A のデータベースコンテキストを変更保存しました。
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}

B のデータベースコンテキストを変更保存します。
B の更新でエラーが発生しました。
The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1300.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}

処理を終了します。

میں اسے حصوں میں تقسیم کروں گا.

Console.WriteLine("Hello, World!");

// 2人が別々にデータベースにアクセスする想定で2つのデータベースコンテキストを作成
Console.WriteLine("データベースコンテキストを作成します。");
using var dbContextA = new TestDatabaseDbContext();
using var dbContextB = new TestDatabaseDbContext();
using var dbContextC = new TestDatabaseDbContext();
Console.WriteLine("データベースコンテキストを作成しました。");

میں دو ڈیٹا بیس سیاق و سباق بنا رہا ہوں، اگر آپ ایک ڈیٹا بیس سیاق و سباق کا اشتراک کرتے ہیں تو ، جب ڈیٹا پڑھا جائے گا تو یہ کیش ہوجائے گا اور یہ ایک ہی مثال ہوگی۔ فرض کریں کہ ہر ایک تک الگ الگ رسائی حاصل کی جاتی ہے ، دو ڈیٹا بیس سیاق و سباق بنائے جاتے ہیں۔ dbContextC ڈیٹا بیس میں اقدار کی جانچ پڑتال کے لئے ہے. مجھے واقعی اس کی ضرورت نہیں ہے کیونکہ اے یا بی کو تبدیل کیا جاسکتا ہے۔

// それぞれがデータを編集しようと読み込む
Console.WriteLine("ID:1 の Book を読み込みます。");
var bookA = dbContextA.Book.First(x => x.ID == 1);
var bookB = dbContextB.Book.First(x => x.ID == 1);
Console.WriteLine("ID:1 の Book を読み込みました。");
Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");

فرض کریں کہ ان تک الگ سے رسائی حاصل کی جاتی ہے ، وہ مختلف ڈیٹا بیس سیاق و سباق Book سے ایک پڑھ رہے ہیں۔ اس وقت، ہم نے کچھ بھی تبدیل نہیں کیا ہے، لہذا وہ سب ایک جیسے ہیں.

ID:1 の Book を読み込みます。
ID:1 の Book を読み込みました。
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}

سب سے پہلے، میں نے مسٹر / مس کی کتاب کو تبدیل اور اپ ڈیٹ کیا. اپ ڈیٹ کے عمل کا خلاصہ ایک طریقہ کار میں کیا جاتا ہے UpdateToDatabase ، اور جب کوئی استثنا ہوتا ہے تو ایک پیغام دکھایا جاتا ہے۔

// A の人が最初にデータベースに更新する
bookA.Price += 500;
UpdateToDatabase(dbContextA, "A");

Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");
A のデータベースコンテキストを変更保存します。
A のデータベースコンテキストを変更保存しました。
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1000.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}

اس کے نتیجے میں ، اسے کامیابی سے اپ ڈیٹ کیا گیا ہے ، اور Price RowVersion کتاب اے کو اپ ڈیٹ کیا گیا ہے۔ اس کے علاوہ ، اگر آپ براہ راست ڈی بی ویلیو پڑھتے ہیں تو ، تازہ ترین قیمت اپ ڈیٹ شدہ قیمت کے برابر ہوگی۔ میں اسے اپ ڈیٹ کرنے کے قابل تھا کیونکہ دونوں اے RowVersion اور RowVersion ڈی بی میں تھے AAAAAAAAH2k= ۔ اپ ڈیٹ کی وجہ سے ورژن بدل گیا AAAAAAAAH2o= ہے۔

اے کو اپ ڈیٹ کرنے کے بعد ، اسی طرح بی کو اپ ڈیٹ کریں۔

// そのあと B の人が最初にデータベースに更新する
bookB.Price += 300;
UpdateToDatabase(dbContextB, "B");

Console.WriteLine($"A  Book : {JsonSerializer.Serialize(bookA)}");
Console.WriteLine($"B  Book : {JsonSerializer.Serialize(bookB)}");
Console.WriteLine($"DB Book : {JsonSerializer.Serialize(dbContextC.Book.AsNoTracking().First(x => x.ID == 1))}");
B のデータベースコンテキストを変更保存します。
B の更新でエラーが発生しました。
The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
A  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}
B  Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1300.0000,"RowVersion":"AAAAAAAAH2k="}
DB Book : {"ID":1,"Name":"C#\u306E\u672C","Price":1500.0000,"RowVersion":"AAAAAAAAH2o="}

نتیجہ ایک استثناء DbUpdateConcurrencyException ہے اور اپ ڈیٹ ناکام ہوگئی ہے۔ bookB.RowVersion AAAAAAAAH2k= یہ ہے ، لیکن RowVersion چونکہ پہلے سے ہی AAAAAAAAH2o= ہے ، لہذا اس کو ایک بے ترتیب سمجھا جاتا ہے اور اپ ڈیٹ کی غلطی واقع ہوتی ہے۔ آپ دیکھ سکتے Price ہیں کہ مقامی متغیر bookB بدل گیا ہے، لیکن RowVersion آپ دیکھ سکتے ہیں کہ ڈیٹا بیس سائیڈ پر اقدار بالکل تبدیل نہیں ہوئی ہیں۔

خلاصہ

یہ نافذ کرنے کے لئے متعدد لاک اقسام میں سے سب سے آسان ہے ، کیونکہ جب آپ ایس کیو ایل سرور اور اینٹیٹی فریم ورک کور میں خود کار طریقے سے تیار کردہ کوڈ استعمال کرتے ہیں تو ، پرامید کنکرنسی پہلے سے طے شدہ طور پر لاگو ہوتی ہے۔ تاہم ، چونکہ یہ صرف "ڈیٹا کرپشن کو اپ ڈیٹ کرنے" کو روکنے کے لئے ہے ، لہذا جب دیگر ڈیٹا شامل ہوتا ہے یا صارف کی کارروائیاں شامل ہوتی ہیں تو استثنیات کو مناسب طریقے سے سنبھالنا ضروری ہے۔

اس کے علاوہ ، اس بار میں نے کچھ بھی منظم نہیں کیا کیونکہ میں نے اسے ایک سادہ کنسول ایپلی کیشن میں لاگو کیا RowVersion تھا۔ اگر آپ کسی ویب ایپلی کیشن یا کلائنٹ ایپلی کیشن میں ڈیٹا لوڈ کرنے کے بعد ترمیم اسکرین داخل کرنا چاہتے ہیں تو، RowVersion کسی طرح سے تاکہ اپ ڈیٹ ہونے پر اس کا مناسب تعین کیا جا سکے۔

تاہم ، اینٹیٹی فریم ورک کور میں تبدیلی ٹریکنگ فنکشن ہے ، لہذا اگر آپ اپ ڈیٹ کے وقت ڈی بی سے پڑھنے والی قیمت پر پرانے RowVersion کو سیٹ کرنا چاہتے ہیں تو ،

bookB.RowVersion = <古い RowVersion>;

یہاں تک کہ اگر اسے مندرجہ ذیل طور پر سیٹ کیا جاتا ہے تو ، اسے "پرامید کنکرنسی کنٹرول" کے طور پر صحیح طریقے سے فیصلہ نہیں کیا جائے گا۔ RowVersion یہاں تک کہ اگر آپ قیمت کو عام طور پر مقرر کرتے ہیں تو ، اسے صرف تبدیل شدہ قدر کے طور پر تسلیم کیا جائے گا ، لہذا مندرجہ ذیل ہے۔

dbContextB.Entry(bookB).Property("RowVersion").OriginalValue = <古い RowVersion>;

تبدیلی سے پہلے قیمت کو دوبارہ لکھنا ضروری ہے۔