Merge pull request 'feat: add BaseDbContext, non-generic IEntity, fix Entity constructor' (#1) from fix/entity-base-improvements into development
This commit was merged in pull request #1.
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- HrynCo shared packages -->
|
||||
<PackageVersion Include="HrynCo.Common" Version="1.0.0" />
|
||||
<!-- Entity Framework Core -->
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5" />
|
||||
|
||||
@@ -14,12 +14,10 @@ public abstract class Entity : Entity<Guid>
|
||||
protected Entity()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Created = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
protected Entity(Guid id)
|
||||
{
|
||||
Id = id;
|
||||
Created = DateTimeOffset.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
namespace HrynCo.DAL.Abstract.Entities;
|
||||
|
||||
public interface IEntity<TId> where TId : struct
|
||||
public interface IEntity
|
||||
{
|
||||
TId Id { get; set; }
|
||||
DateTimeOffset Created { get; set; }
|
||||
DateTimeOffset? Updated { get; set; }
|
||||
}
|
||||
|
||||
public interface IEntity<TId> : IEntity where TId : struct
|
||||
{
|
||||
TId Id { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace HrynCo.DAL.EF.Converters;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
internal class UtcValueConverter()
|
||||
: ValueConverter<DateTime, DateTime>(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
|
||||
@@ -0,0 +1,74 @@
|
||||
namespace HrynCo.DAL.EF.Core;
|
||||
|
||||
using HrynCo.Common;
|
||||
using HrynCo.DAL.Abstract.Entities;
|
||||
using HrynCo.DAL.EF.Converters;
|
||||
using HrynCo.DAL.EF.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
public abstract class BaseDbContext : DbContext
|
||||
{
|
||||
private readonly IClock _clock;
|
||||
|
||||
protected BaseDbContext(DbContextOptions options, IClock clock)
|
||||
: base(options)
|
||||
{
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
public override int SaveChanges()
|
||||
{
|
||||
ApplyTimestamps();
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
ApplyTimestamps();
|
||||
return await base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private void ApplyTimestamps()
|
||||
{
|
||||
DateTimeOffset now = _clock.UtcNow;
|
||||
|
||||
foreach (EntityEntry<IEntity> entry in ChangeTracker.Entries<IEntity>())
|
||||
{
|
||||
switch (entry.State)
|
||||
{
|
||||
case EntityState.Added:
|
||||
entry.Entity.Created = now;
|
||||
break;
|
||||
case EntityState.Modified:
|
||||
entry.Entity.Updated = now;
|
||||
break;
|
||||
case EntityState.Detached:
|
||||
case EntityState.Unchanged:
|
||||
case EntityState.Deleted:
|
||||
break;
|
||||
default:
|
||||
throw new UnexpectedEntityStateException(entry.State);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
|
||||
{
|
||||
configurationBuilder.Properties<DateTime>().HaveConversion<UtcValueConverter>();
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
foreach (IMutableForeignKey relationship in modelBuilder.Model.GetEntityTypes()
|
||||
.SelectMany(e => e.GetForeignKeys()))
|
||||
{
|
||||
relationship.DeleteBehavior = DeleteBehavior.Restrict;
|
||||
}
|
||||
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
|
||||
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace HrynCo.DAL.EF.Exceptions;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public sealed class UnexpectedEntityStateException : Exception
|
||||
{
|
||||
public UnexpectedEntityStateException(EntityState state)
|
||||
: base($"Unexpected entity state: {state}")
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HrynCo.Common" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
Reference in New Issue
Block a user