Skip to content

Commit a879f33

Browse files
[release/10.0] Fix TableSharingConcurrencyTokenConvention to skip JSON-mapped entities (#37286)
Fixes #37274 Co-authored-by: AndriySvyryd <[email protected]>
1 parent e421899 commit a879f33

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ public virtual void ProcessModelFinalizing(
7878
{
7979
Check.DebugAssert(readOnlyProperties.Count != 0, $"No properties mapped to column '{concurrencyColumnName}'");
8080

81+
// JSON-mapped entities don't have column names for their properties,
82+
// so we skip them as they participate in the owner's concurrency token
83+
if (entityType.IsMappedToJson())
84+
{
85+
continue;
86+
}
87+
8188
var foundMappedProperty = !IsConcurrencyTokenMissing(readOnlyProperties, entityType, mappedTypes)
8289
|| entityType.GetProperties()
8390
.Any(p => p.GetColumnName(table) == concurrencyColumnName);

test/EFCore.Relational.Tests/Metadata/Conventions/TableSharingConcurrencyTokenConventionTest.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,55 @@ public virtual void Concurrency_token_property_is_not_created_on_the_sharing_whe
202202
Assert.All(animalEntityType.GetProperties(), p => Assert.NotEqual(typeof(byte[]), p.ClrType));
203203
}
204204

205+
[ConditionalFact]
206+
public virtual void Missing_concurrency_token_property_is_not_created_for_json_mapped_entity()
207+
{
208+
var modelBuilder = GetModelBuilder();
209+
modelBuilder.Entity<BaseEntity>(b =>
210+
{
211+
b.HasKey(e => e.Id);
212+
b.Property(e => e.RowVersion).IsRowVersion().IsConcurrencyToken();
213+
b.Property(e => e.Name).HasMaxLength(100).IsRequired();
214+
b.HasDiscriminator<string>("Type")
215+
.HasValue<DerivedEntity>(nameof(DerivedEntity));
216+
});
217+
modelBuilder.Entity<DerivedEntity>(b =>
218+
{
219+
b.OwnsOne(x => x.Owned, ob =>
220+
{
221+
ob.ToJson();
222+
ob.Property(o => o.Description).HasMaxLength(200).IsRequired();
223+
});
224+
});
225+
226+
var model = modelBuilder.Model;
227+
model.FinalizeModel();
228+
229+
var ownedEntity = model.FindEntityType(typeof(OwnedEntity));
230+
Assert.NotNull(ownedEntity);
231+
Assert.True(ownedEntity.IsMappedToJson());
232+
Assert.DoesNotContain(
233+
ownedEntity.GetProperties(),
234+
p => p.Name.StartsWith("_TableSharingConcurrencyTokenConvention"));
235+
}
236+
237+
protected abstract class BaseEntity
238+
{
239+
public int Id { get; set; }
240+
public string Name { get; set; } = string.Empty;
241+
public long RowVersion { get; set; }
242+
}
243+
244+
protected class DerivedEntity : BaseEntity
245+
{
246+
public OwnedEntity Owned { get; set; } = new();
247+
}
248+
249+
protected class OwnedEntity
250+
{
251+
public string Description { get; set; } = "Any";
252+
}
253+
205254
protected class Animal
206255
{
207256
public int Id { get; set; }

0 commit comments

Comments
 (0)