Description
openedon Nov 8, 2022
I am using a sample application where I have defined [ConcurrencyCheck] for entity property 'Contact'.
public class Author
{
public int Id { get; set; }
[ConcurrencyCheck]
public string Name { get; set; }
[ConcurrencyCheck]
public ContactDetails Contact { get; set; }
}
I am configuring this property as ToJson() in OnModelCreating().
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>().OwnsOne(
author => author.Contact, ownedNavigationBuilder =>
{
ownedNavigationBuilder.ToJson();
ownedNavigationBuilder.OwnsOne(contactDetails => contactDetails.Address);
});
}
After creating the table using code-first and populating the data, I am trying to update the phone number of Contact column.
Here is the Sql that gets generated to update field.
Executed DbCommand (21ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (DbType = Int32), @p2='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
UPDATE [Authors] SET [Contact] = JSON_MODIFY([Contact], 'strict $.Phone', JSON_VALUE(@p0, '$[0]'))
OUTPUT 1
WHERE [Id] = @p1 AND [Name] = @p2;
Generated sql doesn't have any filter based on 'Contact' column even if I have used [ConcurrencyCheck] for corresponding entity property. So it doesn't seem Concurrency is being honored for Contact column.
Please could someone clarify if Concurrency is supported for aggregate types for which ToJson() is defined.
If yes, how do we support it? What am I missing in my sample application.
If not, are there any future plans on supporting this?
Sample Application
using System;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.ComponentModel.DataAnnotations;
namespace test
{
class Program
{
public class ContactDetails
{
public Address Address { get; set; } = null!;
public string? Phone { get; set; }
}
public class Address
{
public Address(string street, string city, string postcode, string country)
{
Street = street;
City = city;
Postcode = postcode;
Country = country;
}
public string Street { get; set; }
public string City { get; set; }
public string Postcode { get; set; }
public string Country { get; set; }
}
public class Author
{
public int Id { get; set; }
[ConcurrencyCheck]
public string Name { get; set; }
[ConcurrencyCheck]
public ContactDetails Contact { get; set; }
}
public class AuthorContext : DbContext
{
public DbSet<Author> Authors { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"<connection_string>").LogTo(Console.WriteLine);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>().OwnsOne(
author => author.Contact, ownedNavigationBuilder =>
{
ownedNavigationBuilder.ToJson();
ownedNavigationBuilder.OwnsOne(contactDetails => contactDetails.Address);
});
}
public static void Main()
{
using (var context = new AuthorContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var author1 = new Author()
{
Name = "Maddy Montaquila",
Contact = new ContactDetails()
{
Phone = "01632 12345",
Address = new Address("1 Main St", "Camberwick Green", "CW1 5ZH", "UK")
}
};
var author2 = new Author()
{
Name = "Jeremy Likness",
Contact = new ContactDetails()
{
Phone = "01632 12346",
Address = new Address("2 Main St", "Chigley", "CH1 5ZH", "UK")
}
};
context.Authors.Add(author1);
context.Authors.Add(author2);
context.SaveChanges();
var authorsInChigley = context.Authors
.Where(author => author.Contact.Phone == "01632 12346")
.ToList();
foreach (Author author in authorsInChigley)
{
author.Contact.Phone = "01234 56789";
}
context.SaveChanges();
}
}
}
}
}
Provider and version information
EF Core version: 7.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.2.6