Skip to content

Commit 5f21edc

Browse files
DOCSP-42175 Concurrency Fundamentals (#32)
1 parent 31d0dc1 commit 5f21edc

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

source/fundamentals.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ Fundamentals
1414
/fundamentals/configure
1515
/fundamentals/query-data
1616
/fundamentals/write-data
17+
/fundamentals/optimistic-concurrency
1718

1819
- :ref:`entity-framework-configure`
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
.. _entity-framework-optimistic-concurrency:
2+
3+
===================================================
4+
Ensure Data Consistency with Optimistic Concurrency
5+
===================================================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: transaction, EF, EF Core, code example
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to use **optimistic concurrency control** with the
24+
{+provider-short+}. Optimistic concurrency control ensures that data is not
25+
overwritten between the time an application reads it and the time the
26+
application writes it back to the database. The {+provider-short+} supports two
27+
ways to implement optimistic concurrency control:
28+
29+
- Concurrency tokens, by using the ``ConcurrencyCheck`` attribute or the
30+
``IsConcurrencyToken()`` fluent API method
31+
- Row versioning, by using the ``Timestamp`` attribute or the
32+
``IsRowVersion()`` fluent API method
33+
34+
.. tip::
35+
36+
We recommend ensuring optimistic concurrency by using only one of the
37+
preceding implementations per entity.
38+
39+
Concurrency Tokens
40+
------------------
41+
42+
You can ensure optimistic concurrency on a specified property by using a
43+
concurrency token. When querying the entity, the {+provider-short+} tracks the concurrency token.
44+
Then, when the provider calls the ``SaveChanges()`` or ``SaveChangesAsync()``
45+
method, it compares the value of the concurrency token the value saved in
46+
the database to ensure that the original value hasn't changed.
47+
48+
You can configure a concurrency token by specifying the ``ConcurrencyCheck``
49+
attribute when defining a class. The following example shows how to specify the
50+
``ConcurrencyCheck`` attribute on the ``LastModified`` property of a ``Customer`` class:
51+
52+
.. code-block:: csharp
53+
:emphasize-lines: 6-7
54+
55+
public class Customer
56+
{
57+
public ObjectId Id { get; set; }
58+
public String Name { get; set; }
59+
public String Order { get; set; }
60+
[ConcurrencyCheck]
61+
public DateTimeOffset LastModified { get; set; }
62+
}
63+
64+
You can also configure a concurrency token by using the
65+
``IsConcurrencyToken()`` method. Call the ``IsConcurrencyToken()`` method in the
66+
``OnModelCreating()`` method of the ``DbContext`` class, as shown in the
67+
following example:
68+
69+
.. literalinclude:: /includes/fundamentals/code-examples/DbContextConcurrency.cs
70+
:start-after: // start-concurrency-token
71+
:end-before: // end-concurrency-token
72+
:language: csharp
73+
:emphasize-lines: 4-6
74+
75+
The {+provider-short+} supports setting concurrency tokens on any property type
76+
supported by the driver. You can also set multiple concurrency tokens on a
77+
single entity. If you need to update a concurrency token, you must do so
78+
manually.
79+
80+
Row Versioning
81+
--------------
82+
83+
You can ensure optimistic concurrency by using row versioning. Row
84+
versioning allows you to track changes to an entity by specifying a version field that
85+
increments automatically when the entity changes. You can configure row
86+
versioning by specifying the ``Timestamp`` attribute when defining a class. The
87+
following example shows how to specify the ``Timestamp`` attribute on the
88+
``Version`` property of a ``Customer`` class:
89+
90+
.. code-block:: csharp
91+
:emphasize-lines: 6-7
92+
93+
public class Customer
94+
{
95+
public ObjectId Id { get; set; }
96+
public String Name { get; set; }
97+
public String Order { get; set; }
98+
[Timestamp]
99+
public long Version { get; set; }
100+
}
101+
102+
You can also configure row versioning by using the ``IsRowVersion()`` method.
103+
Call the ``IsRowVersion()`` method in the ``OnModelCreating()`` method of the
104+
``DbContext`` class, as shown in the following example:
105+
106+
.. literalinclude:: /includes/fundamentals/code-examples/DbContextConcurrency.cs
107+
:start-after: // start-row-version
108+
:end-before: // end-row-version
109+
:language: csharp
110+
:emphasize-lines: 4-6
111+
112+
The {+provider-short+} supports row versioning on only a single property
113+
of an entity. The property must be of type ``long``, ``int``, ``ulong``, or
114+
``uint``.
115+
116+
Limitations
117+
-----------
118+
119+
Consider the following limitations when configuring optimistic concurrency
120+
control on a database that shares data with other applications:
121+
122+
- Other applications must support the same mechanisms you are using for
123+
optimistic concurrency control in your {+framework-core+} application.
124+
- Other applications must support checks for concurrency tokens and row version
125+
fields during any update or delete operation.
126+
- If you are using row versioning, other applications must map row versioned
127+
fields to the property's name followed by the string: ``_version``. The
128+
application must increment the field's value by 1 for each update.
129+
130+
Additional Information
131+
----------------------
132+
133+
For more information about optimistic concurrency control with
134+
{+framework-core+}, see `Optimistic Concurrency
135+
<https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=data-annotations#optimistic-concurrency>`__
136+
in the Microsoft {+framework-core+} documentation.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// start-concurrency-token
2+
protected override void OnModelCreating(ModelBuilder modelBuilder)
3+
{
4+
base.OnModelCreating(modelBuilder);
5+
modelBuilder.Entity<Customer>()
6+
.Property(p => p.LastModified)
7+
.IsConcurrencyToken();
8+
}
9+
// end-concurrency-token
10+
11+
// start-row-version
12+
protected override void OnModelCreating(ModelBuilder modelBuilder)
13+
{
14+
base.OnModelCreating(modelBuilder);
15+
modelBuilder.Entity<Customer>()
16+
.Property(p => p.Version)
17+
.IsRowVersion();
18+
}
19+
// end-row-version

0 commit comments

Comments
 (0)