आशावादी संगामिति नियंत्रण एकाधिक पहुँच (SQL सर्वर) के साथ अंतिम-जीत अद्यतन के कारण डेटा हानि को रोकता है

पेज अद्यतन :
पेज निर्माण की तारीख :

परिचालन का वातावरण

विजुअल स्टूडियो
  • विजुअल स्टूडियो 2022
।जाल
  • .नेट 8
एंटिटी फ्रेमवर्क कोर
  • एंटिटी फ्रेमवर्क कोर 8.0
SQL सर्वर
  • SQL सर्वर 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 निर्दिष्ट करके, हर बार रिकॉर्ड अपडेट होने पर संस्करण स्वचालित रूप से बढ़ जाता है। इसके अलावा, चूंकि इस संस्करण को प्रति-तालिका के आधार पर प्रबंधित किया जाता है, इसलिए मूल रूप से उसी संस्करण का कोई रिकॉर्ड नहीं है जब तक कि आप इसे मैन्युअल रूप से सेट नहीं करते।

रिकॉर्ड जोड़ें

आप इसे निम्न SQL के साथ जोड़ सकते हैं:

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 आप देख सकते हैं कि डेटाबेस पक्ष पर मान बिल्कुल नहीं बदले हैं।

सारांश

यह लागू करने के लिए कई लॉक प्रकारों में से सबसे आसान है, क्योंकि जब आप SQL सर्वर और एंटिटी फ्रेमवर्क कोर में ऑटो-जेनरेट किए गए कोड का उपयोग करते हैं, तो आशावादी संगामिति डिफ़ॉल्ट रूप से लागू होती है। हालांकि, चूंकि यह केवल "डेटा भ्रष्टाचार को अद्यतन करने" को रोकने के लिए है, इसलिए अपवादों को ठीक से संभालना आवश्यक है जब अन्य डेटा शामिल हो या उपयोगकर्ता संचालन शामिल हों।

इसके अलावा, इस बार मैंने कुछ भी प्रबंधित नहीं किया क्योंकि मैंने इसे एक साधारण कंसोल एप्लिकेशन में लागू किया RowVersion था। यदि आप किसी वेब एप्लिकेशन या क्लाइंट एप्लिकेशन में डेटा लोड करने के बाद संपादन स्क्रीन सम्मिलित करना चाहते हैं, RowVersion किसी तरह से ताकि इसे अपडेट होने पर ठीक से निर्धारित किया जा सके।

हालांकि, एंटिटी फ्रेमवर्क कोर में एक परिवर्तन ट्रैकिंग फ़ंक्शन है, इसलिए यदि आप अपडेट के समय डीबी से पढ़े गए मूल्य के लिए पुराने RowVersion को सेट करना चाहते हैं,

bookB.RowVersion = <古い RowVersion>;

यहां तक कि अगर इसे निम्नानुसार सेट किया गया है, तो इसे "आशावादी संगामिति नियंत्रण" के रूप में सही ढंग से आंका नहीं जाएगा। RowVersion यहां तक कि अगर आप मान को सामान्य रूप से सेट करते हैं, तो इसे केवल परिवर्तित मान के रूप में पहचाना जाएगा, इसलिए निम्नलिखित है

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

परिवर्तन से पहले मूल्य को फिर से लिखना आवश्यक है।