Skip to content

Commit

Permalink
fix: configure concurrency token on aggregate roots
Browse files Browse the repository at this point in the history
  • Loading branch information
PHILLIPS71 committed Jun 3, 2024
1 parent fd6c246 commit 7735259
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 45 deletions.
27 changes: 14 additions & 13 deletions src/Infrastructure/src/EntityFrameworkCore/GiantnodesDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace Giantnodes.Infrastructure.EntityFrameworkCore;

#pragma warning disable S3011

/// <summary>
/// A custom implementation of <see cref="DbContext"/> that provides additional functionality for auditing,
/// soft deletes, and concurrency handling.
Expand All @@ -17,9 +18,9 @@ namespace Giantnodes.Infrastructure.EntityFrameworkCore;
public class GiantnodesDbContext<TDbContext> : DbContext
where TDbContext : DbContext
{
private static readonly MethodInfo? ConfigureAuditPropertiesMethodInfo
private static readonly MethodInfo? ConfigureGlobalPropertiesMethodInfo
= typeof(GiantnodesDbContext<TDbContext>)
.GetMethod(nameof(ConfigureAuditProperties), BindingFlags.Instance | BindingFlags.NonPublic);
.GetMethod(nameof(ConfigureGlobalProperties), BindingFlags.Instance | BindingFlags.NonPublic);

private static readonly MethodInfo? ConfigureIdValueGeneratedMethodInfo
= typeof(GiantnodesDbContext<TDbContext>)
Expand All @@ -45,17 +46,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

foreach (var type in modelBuilder.Model.GetEntityTypes())
{
ConfigureAuditPropertiesMethodInfo?
ConfigureGlobalPropertiesMethodInfo?
.MakeGenericMethod(type.ClrType)
.Invoke(this, [modelBuilder, type]);

ConfigureIdValueGeneratedMethodInfo?
.MakeGenericMethod(type.ClrType)
.Invoke(this, [modelBuilder, type]);

// ConfigureConcurrencyTokenMethodInfo?
// .MakeGenericMethod(type.ClrType)
// .Invoke(this, [modelBuilder, type]);
ConfigureConcurrencyTokenMethodInfo?
.MakeGenericMethod(type.ClrType)
.Invoke(this, [modelBuilder, type]);
}
}

Expand All @@ -82,12 +83,12 @@ public override Task<int> SaveChangesAsync(CancellationToken cancellationToken =
}

/// <summary>
/// Configures audit properties for the specified <typeparamref name="TEntity"/>.
/// Configures global properties for the specified <typeparamref name="TEntity"/>.
/// </summary>
/// <param name="builder">The builder being used to construct the model for this context.</param>
/// <param name="mutable">The mutable entity type for the <typeparamref name="TEntity"/>.</param>
/// <typeparam name="TEntity">The entity type to configure audit properties for.</typeparam>
protected void ConfigureAuditProperties<TEntity>(ModelBuilder builder, IMutableEntityType mutable)
protected void ConfigureGlobalProperties<TEntity>(ModelBuilder builder, IMutableEntityType mutable)
where TEntity : class
{
if (mutable.IsOwned())
Expand Down Expand Up @@ -121,12 +122,11 @@ protected void ConfigureIdValueGenerated<TEntity>(ModelBuilder builder, IMutable
}

/// <summary>
/// Configures the <see cref="IHasConcurrencyToken.ConcurrencyToken"/> property for entities implementing
/// <see cref="IHasConcurrencyToken"/> to be a row version, enabling optimistic concurrency control.
/// Configures the concurrency token property for the given entity type.
/// </summary>
/// <param name="builder">The builder being used to construct the model for this context.</param>
/// <param name="mutable">The mutable entity type for the <typeparamref name="TEntity"/>.</param>
/// <typeparam name="TEntity">The entity type to configure the concurrency token property for.</typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="builder">The model builder.</param>
/// <param name="mutable">The mutable entity type.</param>
protected void ConfigureConcurrencyToken<TEntity>(ModelBuilder builder, IMutableEntityType mutable)
where TEntity : class
{
Expand Down Expand Up @@ -213,6 +213,7 @@ private void SetSoftDeleteEntityProperties()
continue;

entry.Reload();

ObjectHelper.SetProperty(entry.Entity, x => x.IsDeleted, _ => true);
ObjectHelper.SetProperty(entry.Entity, x => x.DeletedAt, _ => DateTime.UtcNow);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public abstract class AggregateRoot : Entity, IAggregateRoot, IHasConcurrencyTok
{
public readonly ICollection<DomainEvent> DomainEvents = new List<DomainEvent>();

public byte[]? ConcurrencyToken { get; private set; }
public uint ConcurrencyToken { get; private set; }
}

/// <inheritdoc cref="IAggregateRoot{TKey}" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ public interface IHasConcurrencyToken
/// <summary>
/// A concurrency token used as a version of the entity.
/// </summary>
byte[]? ConcurrencyToken { get; }
uint ConcurrencyToken { get; }
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
is_watched = table.Column<bool>(type: "boolean", nullable: false),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
concurrency_token = table.Column<Guid>(type: "uuid", nullable: false)
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
},
constraints: table =>
{
Expand Down Expand Up @@ -151,7 +151,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
deleted_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
concurrency_token = table.Column<Guid>(type: "uuid", nullable: false)
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
},
constraints: table =>
{
Expand All @@ -175,7 +175,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
path_info_extension = table.Column<string>(type: "text", nullable: true),
path_info_directory_path = table.Column<string>(type: "text", nullable: true),
path_info_directory_separator_char = table.Column<char>(type: "character(1)", nullable: false),
concurrency_token = table.Column<Guid>(type: "uuid", nullable: false)
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
},
constraints: table =>
{
Expand Down Expand Up @@ -213,7 +213,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
path_info_extension = table.Column<string>(type: "text", nullable: true),
path_info_directory_path = table.Column<string>(type: "text", nullable: true),
path_info_directory_separator_char = table.Column<char>(type: "character(1)", nullable: false),
concurrency_token = table.Column<Guid>(type: "uuid", nullable: false)
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
},
constraints: table =>
{
Expand Down Expand Up @@ -259,7 +259,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
completed_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
concurrency_token = table.Column<Guid>(type: "uuid", nullable: false)
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
},
constraints: table =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("timestamp with time zone")
.HasColumnName("completed_at");

b.Property<Guid>("ConcurrencyToken")
b.Property<uint>("ConcurrencyToken")
.IsConcurrencyToken()
.HasColumnType("uuid")
.HasColumnName("concurrency_token");
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
Expand Down Expand Up @@ -145,10 +146,11 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("uuid")
.HasColumnName("id");

b.Property<Guid>("ConcurrencyToken")
b.Property<uint>("ConcurrencyToken")
.IsConcurrencyToken()
.HasColumnType("uuid")
.HasColumnName("concurrency_token");
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
Expand Down Expand Up @@ -191,10 +193,11 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("uuid")
.HasColumnName("id");

b.Property<Guid>("ConcurrencyToken")
b.Property<uint>("ConcurrencyToken")
.IsConcurrencyToken()
.HasColumnType("uuid")
.HasColumnName("concurrency_token");
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
Expand Down Expand Up @@ -247,10 +250,11 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("integer")
.HasColumnName("codec");

b.Property<Guid>("ConcurrencyToken")
b.Property<uint>("ConcurrencyToken")
.IsConcurrencyToken()
.HasColumnType("uuid")
.HasColumnName("concurrency_token");
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b.Property<int?>("Container")
.HasColumnType("integer")
Expand Down Expand Up @@ -974,6 +978,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("text")
.HasColumnName("path_info_name");

b1.Property<uint>("_TableSharingConcurrencyTokenConvention_ConcurrencyToken")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b1.HasKey("FileSystemDirectoryId");

b1.ToTable("file_system_directories", "orchestrator");
Expand Down Expand Up @@ -1073,6 +1083,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("text")
.HasColumnName("path_info_name");

b1.Property<uint>("_TableSharingConcurrencyTokenConvention_ConcurrencyToken")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("xid")
.HasColumnName("xmin");

b1.HasKey("FileSystemFileId");

b1.ToTable("file_system_files", "orchestrator");
Expand Down

0 comments on commit 7735259

Please sign in to comment.