Skip to content

Commit 88e7f17

Browse files
authored
Merge pull request #20 from koenbeuk/trigger-priority-logic
Fixed trigger priority logic
2 parents c7a2ba4 + ccec97d commit 88e7f17

File tree

2 files changed

+90
-29
lines changed

2 files changed

+90
-29
lines changed

src/EntityFrameworkCore.Triggered/TriggerSession.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,31 @@ public async Task RaiseTriggers(Type openTriggerType, ITriggerContextDiscoverySt
4646
cancellationToken.ThrowIfCancellationRequested();
4747

4848
var triggerContextDescriptors = triggerContextDiscoveryStrategy.Discover(_options, _tracker, _logger);
49-
50-
foreach (var triggerContextDescriptor in triggerContextDescriptors)
49+
IEnumerable<(ITriggerContextDescriptor triggerContextDescriptor, TriggerDescriptor triggerDescriptor)> triggerInvocations = triggerContextDescriptors
50+
.SelectMany(triggerContextDescriptor =>
51+
_triggerDiscoveryService
52+
.DiscoverTriggers(openTriggerType, triggerContextDescriptor.EntityType, triggerTypeDescriptorFactory)
53+
.Select(triggerDescriptor => (triggerContextDescriptor, triggerDescriptor))
54+
)
55+
.OrderBy(x => x.triggerDescriptor.Priority);
56+
57+
if (_logger.IsEnabled(LogLevel.Debug))
5158
{
52-
var triggerDescriptors = _triggerDiscoveryService
53-
.DiscoverTriggers(openTriggerType, triggerContextDescriptor.EntityType, triggerTypeDescriptorFactory)
54-
.ToList();
5559

56-
_logger.LogDebug("Discovered {triggers} triggers for change of type {entityType}", triggerDescriptors.Count(), triggerContextDescriptor.EntityType);
60+
triggerInvocations = triggerInvocations.ToList();
61+
_logger.LogDebug("Discovered {triggers} triggers of type {openTriggerType}", triggerInvocations.Count(), openTriggerType);
62+
}
5763

58-
foreach (var triggerDescriptor in triggerDescriptors)
59-
{
60-
cancellationToken.ThrowIfCancellationRequested();
64+
foreach (var triggerInvocation in triggerInvocations)
65+
{
66+
cancellationToken.ThrowIfCancellationRequested();
6167

62-
_logger.LogInformation("Invoking trigger: {trigger} as {triggerType}", triggerDescriptor.Trigger.GetType().Name, triggerDescriptor.TypeDescriptor.TriggerType.Name);
63-
await triggerDescriptor.Invoke(triggerContextDescriptor.GetTriggerContext(), cancellationToken).ConfigureAwait(false);
68+
if (_logger.IsEnabled(LogLevel.Information))
69+
{
70+
_logger.LogInformation("Invoking trigger: {trigger} as {triggerType}", triggerInvocation.triggerDescriptor.GetType().Name, triggerInvocation.triggerDescriptor.TypeDescriptor.TriggerType.Name);
6471
}
72+
73+
await triggerInvocation.triggerDescriptor.Invoke(triggerInvocation.triggerContextDescriptor .GetTriggerContext(), cancellationToken).ConfigureAwait(false);
6574
}
6675
}
6776

test/EntityFrameworkCore.Triggered.Tests/TriggerSessionTests.cs

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,22 @@ namespace EntityFrameworkCore.Triggered.Tests
1414
{
1515
public class TriggerSessionTests
1616
{
17-
class TestModel
17+
public class TestModel
1818
{
19-
public Guid Id { get; set; }
19+
public int Id { get; set; }
2020
public string Name { get; set; }
2121
}
2222

23-
class TestDbContext : DbContext
23+
public class TestDbContext : DbContext
2424
{
25+
public TestDbContext(DbContextOptions options) : base(options)
26+
{
27+
}
28+
29+
public TestDbContext()
30+
{
31+
}
32+
2533
public TriggerStub<TestModel> TriggerStub { get; } = new TriggerStub<TestModel>();
2634

2735
public DbSet<TestModel> TestModels { get; set; }
@@ -32,8 +40,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
3240

3341
optionsBuilder.EnableServiceProviderCaching(false);
3442
optionsBuilder.UseInMemoryDatabase("test");
35-
optionsBuilder.UseTriggers(triggerOptions =>
36-
{
43+
optionsBuilder.UseTriggers(triggerOptions => {
3744
triggerOptions.AddTrigger(TriggerStub);
3845
});
3946
}
@@ -71,9 +78,8 @@ public async Task RaiseBeforeSaveTriggers_RaisesOnceOnSimpleAddition()
7178
using var context = new TestDbContext();
7279
var subject = CreateSubject(context);
7380

74-
context.TestModels.Add(new TestModel
75-
{
76-
Id = Guid.NewGuid(),
81+
context.TestModels.Add(new TestModel {
82+
Id = 1,
7783
Name = "test1"
7884
});
7985

@@ -89,7 +95,7 @@ public async Task RaiseAfterSaveTriggers_WithoutCallToRaiseBeforeSaveTriggers_Th
8995
var subject = CreateSubject(context);
9096

9197
context.TestModels.Add(new TestModel {
92-
Id = Guid.NewGuid(),
98+
Id = 1,
9399
Name = "test1"
94100
});
95101

@@ -103,7 +109,7 @@ public async Task RaiseAfterSaveTriggers_RaisesOnceOnSimpleAddition()
103109
var subject = CreateSubject(context);
104110

105111
context.TestModels.Add(new TestModel {
106-
Id = Guid.NewGuid(),
112+
Id = 1,
107113
Name = "test1"
108114
});
109115

@@ -120,7 +126,7 @@ public async Task RaiseBeforeSaveTriggers_ThrowsOnCancelledException()
120126
var subject = CreateSubject(context);
121127

122128
context.TestModels.Add(new TestModel {
123-
Id = Guid.NewGuid(),
129+
Id = 1,
124130
Name = "test1"
125131
});
126132

@@ -136,12 +142,12 @@ public async Task RaiseAfterSaveTriggers_ThrowsOnCancelledException()
136142
var subject = CreateSubject(context);
137143

138144
context.TestModels.Add(new TestModel {
139-
Id = Guid.NewGuid(),
145+
Id = 1,
140146
Name = "test1"
141147
});
142148

143149
subject.DiscoverChanges();
144-
150+
145151
var cancellationTokenSource = new CancellationTokenSource();
146152
cancellationTokenSource.Cancel();
147153

@@ -157,13 +163,13 @@ public async Task RaiseBeforeSaveTriggers_RecursiveCall_SkipsDiscoveredChanges()
157163
context.TriggerStub.BeforeSaveHandler = (_1, _2) => {
158164
if (context.TriggerStub.BeforeSaveInvocations.Count > 1)
159165
{
160-
return Task.CompletedTask;
166+
return Task.CompletedTask;
161167
}
162168
return subject.RaiseBeforeSaveTriggers(default);
163169
};
164-
170+
165171
context.TestModels.Add(new TestModel {
166-
Id = Guid.NewGuid(),
172+
Id = 1,
167173
Name = "test1"
168174
});
169175

@@ -180,7 +186,7 @@ public async Task RaiseBeforeSaveTriggers_SkipDetectedChangesAsTrue_ExcludesDete
180186
var subject = CreateSubject(context);
181187

182188
context.TestModels.Add(new TestModel {
183-
Id = Guid.NewGuid(),
189+
Id = 1,
184190
Name = "test1"
185191
});
186192

@@ -197,7 +203,7 @@ public async Task RaiseBeforeSaveTriggers_SkipDetectedChangesAsFalse_IncludesDet
197203
var subject = CreateSubject(context);
198204

199205
context.TestModels.Add(new TestModel {
200-
Id = Guid.NewGuid(),
206+
Id = 1,
201207
Name = "test1"
202208
});
203209

@@ -206,5 +212,51 @@ public async Task RaiseBeforeSaveTriggers_SkipDetectedChangesAsFalse_IncludesDet
206212

207213
Assert.NotEmpty(context.TriggerStub.BeforeSaveInvocations);
208214
}
215+
216+
[Fact]
217+
public void RaiseBeforeSaveTriggers_MultipleEntities_SortByPriorities()
218+
{
219+
var capturedInvocations = new List<(string, ITriggerContext<TestModel>)>();
220+
221+
var earlyTrigger = new TriggerStub<TestModel> {
222+
Priority = CommonTriggerPriority.Early,
223+
BeforeSaveHandler = (context, _) => {
224+
capturedInvocations.Add(("Early", context));
225+
return Task.CompletedTask;
226+
}
227+
};
228+
229+
var lateTrigger = new TriggerStub<TestModel> {
230+
Priority = CommonTriggerPriority.Late,
231+
BeforeSaveHandler = (context, _) => {
232+
capturedInvocations.Add(("Late", context));
233+
return Task.CompletedTask;
234+
}
235+
};
236+
237+
var serviceProvider = new ServiceCollection()
238+
.AddSingleton<IBeforeSaveTrigger<TestModel>>(lateTrigger)
239+
.AddSingleton<IBeforeSaveTrigger<TestModel>>(earlyTrigger)
240+
.AddTriggeredDbContext<TestDbContext>(options => {
241+
options.UseInMemoryDatabase("Test");
242+
})
243+
.BuildServiceProvider();
244+
245+
var scope = serviceProvider.CreateScope();
246+
var dbContext = scope.ServiceProvider.GetRequiredService<TestDbContext>();
247+
var subject = CreateSubject(dbContext);
248+
249+
dbContext.TestModels.Add(new TestModel { Id = 1 });
250+
dbContext.TestModels.Add(new TestModel { Id = 2 });
251+
252+
subject.RaiseBeforeSaveTriggers();
253+
254+
Assert.Equal(4, capturedInvocations.Count);
255+
Assert.Equal("Early", capturedInvocations[0].Item1);
256+
Assert.Equal("Early", capturedInvocations[1].Item1);
257+
Assert.Equal("Late", capturedInvocations[2].Item1);
258+
Assert.Equal("Late", capturedInvocations[3].Item1);
259+
260+
}
209261
}
210262
}

0 commit comments

Comments
 (0)