Skip to content

Commit 983c9da

Browse files
authored
Merge pull request #61 from WeihanLi/dev
8.0.7
2 parents 69aa632 + d389233 commit 983c9da

File tree

10 files changed

+89
-79
lines changed

10 files changed

+89
-79
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<LangVersion>latest</LangVersion>
77
<ImplicitUsings>enable</ImplicitUsings>
88
<Nullable>enable</Nullable>
9-
<CommonVersion>1.0.66</CommonVersion>
10-
<EFVersion>8.0.6</EFVersion>
9+
<CommonVersion>1.0.67</CommonVersion>
10+
<EFVersion>8.0.7</EFVersion>
1111

1212
<PublishRepositoryUrl>true</PublishRepositoryUrl>
1313
<EmbedUntrackedSources>true</EmbedUntrackedSources>

build.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[string]$SCRIPT = '.\build\build.cs'
22

33
# Install dotnet tool
4-
dotnet tool install --global dotnet-execute
4+
dotnet tool update --global dotnet-execute
55

66
Write-Host "dotnet-exec $SCRIPT --args $ARGS" -ForegroundColor GREEN
77

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
SCRIPT='./build/build.cs'
33

44
# Install tool
5-
dotnet tool install --global dotnet-execute
5+
dotnet tool update --global dotnet-execute
66
export PATH="$PATH:$HOME/.dotnet/tools"
77

88
echo "dotnet-exec $SCRIPT --args=$@"

build/build.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var target = CommandLineParser.Val("target", "Default", args);
22
var apiKey = CommandLineParser.Val("apiKey", "", args);
3-
var stable = CommandLineParser.Val("stable", null, args).ToBoolean();
4-
var noPush = CommandLineParser.Val("noPush", null, args).ToBoolean();
3+
var stable = CommandLineParser.BooleanVal("stable", args: args);
4+
var noPush = CommandLineParser.BooleanVal("noPush", args: args);
55
var branchName = EnvHelper.Val("BUILD_SOURCEBRANCHNAME", "local");
66

77
var solutionPath = "./WeihanLi.EntityFramework.sln";
@@ -112,4 +112,4 @@ async Task ExecuteCommandAsync(string commandText, KeyValuePair<string, string>[
112112
var result = await CommandExecutor.ExecuteCommandAndOutputAsync(commandText);
113113
result.EnsureSuccessExitCode();
114114
Console.WriteLine();
115-
}
115+
}

build/version.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<PropertyGroup>
33
<VersionMajor>8</VersionMajor>
44
<VersionMinor>0</VersionMinor>
5-
<VersionPatch>6</VersionPatch>
6-
<VersionRevision>1</VersionRevision>
5+
<VersionPatch>7</VersionPatch>
6+
<VersionRevision>0</VersionRevision>
77
<VersionPrefix Condition="'$(VersionRevision)'=='0' or '$(VersionRevision)'==''">$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
88
<VersionPrefix Condition="'$(VersionRevision)'!='0'">$(VersionMajor).$(VersionMinor).$(VersionPatch).$(VersionRevision)</VersionPrefix>
99
<VersionSuffix Condition="'$(Configuration)'=='DEBUG'">dev</VersionSuffix>

samples/WeihanLi.EntityFramework.Sample/Program.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public class Program
1717
{
1818
public static void Main(string[] args)
1919
{
20-
SoftDeleteTest();
20+
// SoftDeleteTest();
2121
// RepositoryTest();
22-
// AutoAuditTest();
22+
AutoAuditTest();
2323

2424
Console.WriteLine("completed");
2525
Console.ReadLine();
@@ -62,14 +62,14 @@ private static void AutoAuditTest()
6262
var auditRecords = context.AuditRecords.AsNoTracking().ToArray();
6363
Console.WriteLine(auditRecords.ToJson());
6464
}
65-
65+
ConsoleHelper.ReadLineWithPrompt();
6666
{
6767
var services = new ServiceCollection();
6868
services.AddLogging(builder => builder.AddSimpleConsole());
6969
services.AddDbContext<AutoAuditContext2>((provider, options) =>
7070
{
7171
options.UseSqlite("Data Source=AutoAuditTest2.db");
72-
options.AddInterceptors(ActivatorUtilities.GetServiceOrCreateInstance<AuditInterceptor>(provider));
72+
options.AddInterceptors(provider.GetRequiredService<AuditInterceptor>());
7373
});
7474
services.AddEFAutoAudit(builder =>
7575
{
@@ -141,7 +141,7 @@ private static void AutoAuditTest()
141141
var testEntity = new TestEntity()
142142
{
143143
Extra = new { Name = "Tom" }.ToJson(),
144-
CreatedAt = DateTimeOffset.UtcNow,
144+
CreatedAt = DateTimeOffset.Now,
145145
};
146146
dbContext.TestEntities.Add(testEntity);
147147
dbContext.SaveChanges();
@@ -156,13 +156,13 @@ private static void AutoAuditTest()
156156
var testEntity1 = new TestEntity()
157157
{
158158
Extra = new { Name = "Tom1" }.ToJson(),
159-
CreatedAt = DateTimeOffset.UtcNow,
159+
CreatedAt = DateTimeOffset.Now,
160160
};
161161
dbContext.TestEntities.Add(testEntity1);
162162
var testEntity2 = new TestEntity()
163163
{
164164
Extra = new { Name = "Tom2" }.ToJson(),
165-
CreatedAt = DateTimeOffset.UtcNow,
165+
CreatedAt = DateTimeOffset.Now,
166166
};
167167
dbContext.TestEntities.Add(testEntity2);
168168
dbContext.SaveChanges();
@@ -217,7 +217,7 @@ private static void RepositoryTest()
217217
var repo = db.GetRepository<TestDbContext, TestEntity>();
218218
repo.Insert(new TestEntity()
219219
{
220-
CreatedAt = DateTimeOffset.UtcNow,
220+
CreatedAt = DateTimeOffset.Now,
221221
Extra = "{\"Name\": \"Tom\"}"
222222
});
223223

src/WeihanLi.EntityFramework/Audit/AuditDbContext.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
using Microsoft.EntityFrameworkCore;
22
using Microsoft.Extensions.DependencyInjection;
33
using WeihanLi.Common.Models;
4-
using WeihanLi.Common.Services;
54

65
namespace WeihanLi.EntityFramework.Audit;
76

87
public abstract class AuditDbContextBase(DbContextOptions dbContextOptions, IServiceProvider serviceProvider)
98
: DbContextBase(dbContextOptions)
109
{
1110
private readonly IAuditStore[] _auditStores = serviceProvider.GetServices<IAuditStore>().ToArray();
12-
private readonly IUserIdProvider? _auditUserIdProvider =
13-
AuditConfig.Options.UserIdProviderFactory?.Invoke(serviceProvider);
11+
private readonly IAuditPropertyEnricher[] _auditPropertyEnrichers =
12+
serviceProvider.GetServices<IAuditPropertyEnricher>().ToArray();
13+
private readonly string? _auditUser =
14+
AuditConfig.Options.UserIdProviderFactory?.Invoke(serviceProvider)?.GetUserId();
1415

1516
protected List<AuditEntry>? AuditEntries { get; set; }
1617

@@ -31,6 +32,7 @@ protected override Task BeforeSaveChanges()
3132
{
3233
continue;
3334
}
35+
3436
AuditEntries.Add(new InternalAuditEntry(entityEntry));
3537
}
3638

@@ -41,6 +43,8 @@ protected override async Task AfterSaveChanges()
4143
{
4244
if (AuditEntries is { Count: > 0 })
4345
{
46+
var now = DateTimeOffset.Now;
47+
4448
foreach (var entry in AuditEntries)
4549
{
4650
if (entry is InternalAuditEntry { TemporaryProperties.Count: > 0 } auditEntry)
@@ -75,13 +79,13 @@ protected override async Task AfterSaveChanges()
7579
}
7680

7781
// apply enricher
78-
foreach (var enricher in AuditConfig.Options.Enrichers)
82+
foreach (var enricher in _auditPropertyEnrichers)
7983
{
8084
enricher.Enrich(entry);
8185
}
8286

83-
entry.UpdatedAt = DateTimeOffset.Now;
84-
entry.UpdatedBy = _auditUserIdProvider?.GetUserId();
87+
entry.UpdatedAt = now;
88+
entry.UpdatedBy = _auditUser;
8589
}
8690

8791
await Task.WhenAll(_auditStores.Select(store => store.Save(AuditEntries)));

src/WeihanLi.EntityFramework/Audit/AuditInterceptor.cs

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextE
2222
return base.SavingChangesAsync(eventData, result, cancellationToken);
2323
}
2424

25+
public override int SavedChanges(SaveChangesCompletedEventData eventData, int result)
26+
{
27+
PostSaveChanges().GetAwaiter().GetResult();
28+
var savedChanges = base.SavedChanges(eventData, result);
29+
return savedChanges;
30+
}
31+
32+
public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result,
33+
CancellationToken cancellationToken = default)
34+
{
35+
await PostSaveChanges();
36+
var savedChanges = await base.SavedChangesAsync(eventData, result, cancellationToken);
37+
return savedChanges;
38+
}
39+
2540
private void PreSaveChanges(DbContext dbContext)
2641
{
2742
if (!AuditConfig.Options.AuditEnabled)
@@ -60,52 +75,54 @@ private async Task PostSaveChanges()
6075
{
6176
if (AuditEntries is { Count: > 0 })
6277
{
78+
var now = DateTimeOffset.Now;
79+
6380
var auditUserIdProvider = AuditConfig.Options.UserIdProviderFactory?.Invoke(serviceProvider);
81+
var auditUser = auditUserIdProvider?.GetUserId();
82+
var enrichers = serviceProvider.GetServices<IAuditPropertyEnricher>().ToArray();
6483

6584
foreach (var entry in AuditEntries)
6685
{
67-
if (entry is InternalAuditEntry auditEntry)
86+
// update TemporaryProperties
87+
if (entry is InternalAuditEntry { TemporaryProperties.Count: > 0 } auditEntry)
6888
{
69-
// update TemporaryProperties
70-
if (auditEntry.TemporaryProperties is { Count: > 0 })
89+
foreach (var temporaryProperty in auditEntry.TemporaryProperties)
7190
{
72-
foreach (var temporaryProperty in auditEntry.TemporaryProperties)
91+
var colName = temporaryProperty.GetColumnName();
92+
if (temporaryProperty.Metadata.IsPrimaryKey())
93+
{
94+
auditEntry.KeyValues[colName] = temporaryProperty.CurrentValue;
95+
}
96+
97+
switch (auditEntry.OperationType)
7398
{
74-
var colName = temporaryProperty.GetColumnName();
75-
if (temporaryProperty.Metadata.IsPrimaryKey())
76-
{
77-
auditEntry.KeyValues[colName] = temporaryProperty.CurrentValue;
78-
}
79-
80-
switch (auditEntry.OperationType)
81-
{
82-
case DataOperationType.Add:
83-
auditEntry.NewValues![colName] = temporaryProperty.CurrentValue;
84-
break;
85-
86-
case DataOperationType.Delete:
87-
auditEntry.OriginalValues![colName] = temporaryProperty.OriginalValue;
88-
break;
89-
90-
case DataOperationType.Update:
91-
auditEntry.OriginalValues![colName] = temporaryProperty.OriginalValue;
92-
auditEntry.NewValues![colName] = temporaryProperty.CurrentValue;
93-
break;
94-
}
99+
case DataOperationType.Add:
100+
auditEntry.NewValues![colName] = temporaryProperty.CurrentValue;
101+
break;
102+
103+
case DataOperationType.Delete:
104+
auditEntry.OriginalValues![colName] = temporaryProperty.OriginalValue;
105+
break;
106+
107+
case DataOperationType.Update:
108+
auditEntry.OriginalValues![colName] = temporaryProperty.OriginalValue;
109+
auditEntry.NewValues![colName] = temporaryProperty.CurrentValue;
110+
break;
95111
}
96-
// set to null
97-
auditEntry.TemporaryProperties = null;
98112
}
113+
114+
// set TemporaryProperties to null
115+
auditEntry.TemporaryProperties = null;
99116
}
100117

101118
// apply enricher
102-
foreach (var enricher in AuditConfig.Options.Enrichers)
119+
foreach (var enricher in enrichers)
103120
{
104121
enricher.Enrich(entry);
105122
}
106123

107-
entry.UpdatedAt = DateTimeOffset.UtcNow;
108-
entry.UpdatedBy = auditUserIdProvider?.GetUserId();
124+
entry.UpdatedBy = auditUser;
125+
entry.UpdatedAt = now;
109126
}
110127

111128
await Task.WhenAll(
@@ -114,17 +131,4 @@ await Task.WhenAll(
114131
);
115132
}
116133
}
117-
118-
public override int SavedChanges(SaveChangesCompletedEventData eventData, int result)
119-
{
120-
PostSaveChanges().GetAwaiter().GetResult();
121-
return base.SavedChanges(eventData, result);
122-
}
123-
124-
public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result,
125-
CancellationToken cancellationToken = new CancellationToken())
126-
{
127-
await PostSaveChanges();
128-
return await base.SavedChangesAsync(eventData, result, cancellationToken);
129-
}
130134
}

src/WeihanLi.EntityFramework/Audit/IAuditConfig.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.EntityFrameworkCore.ChangeTracking;
22
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.DependencyInjection.Extensions;
34
using WeihanLi.Common;
45
using WeihanLi.Common.Services;
56

@@ -24,6 +25,9 @@ IAuditConfigBuilder WithUserIdProvider(IUserIdProvider auditUserProvider) =>
2425
IAuditConfigBuilder WithPropertyFilter(Func<EntityEntry, PropertyEntry, bool> propertyFilter);
2526

2627
IAuditConfigBuilder WithEnricher(IAuditPropertyEnricher enricher);
28+
29+
IAuditConfigBuilder WithEnricher<TEnricher>(ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
30+
where TEnricher : IAuditPropertyEnricher;
2731
}
2832

2933
internal sealed class AuditConfigBuilder(IServiceCollection services) : IAuditConfigBuilder
@@ -34,7 +38,6 @@ internal sealed class AuditConfigBuilder(IServiceCollection services) : IAuditCo
3438
var userIdProvider = sp.GetService<IUserIdProvider>();
3539
return userIdProvider ?? EnvironmentUserIdProvider.Instance;
3640
};
37-
private readonly List<IAuditPropertyEnricher> _auditPropertyEnrichers = new();
3841
private readonly List<Func<EntityEntry, bool>> _entityFilters = new();
3942
private readonly List<Func<EntityEntry, PropertyEntry, bool>> _propertyFilters = new();
4043
private bool _saveUnModifiedProperty;
@@ -84,15 +87,21 @@ public IAuditConfigBuilder WithPropertyFilter(Func<EntityEntry, PropertyEntry, b
8487
public IAuditConfigBuilder WithEnricher(IAuditPropertyEnricher enricher)
8588
{
8689
ArgumentNullException.ThrowIfNull(enricher);
87-
_auditPropertyEnrichers.Add(enricher);
90+
services.AddSingleton(enricher);
91+
return this;
92+
}
93+
94+
public IAuditConfigBuilder WithEnricher<TEnricher>(ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
95+
where TEnricher : IAuditPropertyEnricher
96+
{
97+
services.TryAddEnumerable(new ServiceDescriptor(typeof(IAuditPropertyEnricher), typeof(TEnricher), serviceLifetime));
8898
return this;
8999
}
90100

91101
public AuditConfigOptions Build()
92102
{
93103
return new()
94104
{
95-
Enrichers = _auditPropertyEnrichers,
96105
EntityFilters = _entityFilters,
97106
PropertyFilters = _propertyFilters,
98107
UserIdProviderFactory = _auditUserProviderFactory,
@@ -109,14 +118,6 @@ internal sealed class AuditConfigOptions
109118

110119
public Func<IServiceProvider, IUserIdProvider>? UserIdProviderFactory { get; set; }
111120

112-
private IReadOnlyCollection<IAuditPropertyEnricher> _enrichers = Array.Empty<IAuditPropertyEnricher>();
113-
114-
public IReadOnlyCollection<IAuditPropertyEnricher> Enrichers
115-
{
116-
get => _enrichers;
117-
set => _enrichers = Guard.NotNull(value);
118-
}
119-
120121
private IReadOnlyCollection<Func<EntityEntry, bool>> _entityFilters = Array.Empty<Func<EntityEntry, bool>>();
121122

122123
public IReadOnlyCollection<Func<EntityEntry, bool>> EntityFilters

test/WeihanLi.EntityFramework.Test/WeihanLi.EntityFramework.Test.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
5+
<IsTestProject>true</IsTestProject>
56
<IsPackable>false</IsPackable>
67
<Nullable>disable</Nullable>
78
</PropertyGroup>
89

910
<ItemGroup>
1011
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(EFVersion)" />
1112
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(EFVersion)" />
12-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
13-
<PackageReference Include="xunit" Version="2.7.0" />
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
14+
<PackageReference Include="xunit" Version="2.9.0" />
1415
</ItemGroup>
1516

1617
<ItemGroup>

0 commit comments

Comments
 (0)