Skip to content

Commit f771a83

Browse files
authored
Merge pull request #101 from koenbeuk/simplified-perf-tests
Removed competitors from the perf tests
2 parents 75c27d3 + 98c7eb8 commit f771a83

File tree

8 files changed

+25
-210
lines changed

8 files changed

+25
-210
lines changed

benchmarks/EntityFrameworkCore.Triggered.Benchmarks/ApplicationContext.cs

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,18 @@
22
using System.Collections.Generic;
33
using System.Security.Cryptography.X509Certificates;
44
using System.Text;
5-
using Com.Setarit.Ramses;
6-
using Com.Setarit.Ramses.LifecycleListener;
7-
using EntityFrameworkCore.Triggers;
85
using Microsoft.EntityFrameworkCore;
96
using Microsoft.EntityFrameworkCore.Infrastructure;
107

118
namespace EntityFrameworkCore.Triggered.Benchmarks
129
{
13-
public class Student : Com.Setarit.Ramses.LifecycleListener.IBeforeAddingListener
10+
public class Student
1411
{
1512
public Guid Id { get; set; }
1613

1714
public string DisplayName { get; set; }
1815

1916
public DateTimeOffset RegistrationDate { get; set; }
20-
21-
void IBeforeAddingListener.BeforeAdding()
22-
{
23-
this.RegistrationDate = DateTimeOffset.Now;
24-
}
2517
}
2618

2719
public class Course
@@ -76,25 +68,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
7668
public DbSet<StudentCourse> StudentCourses { get; set; }
7769
}
7870

79-
public class ApplicationContextWithTriggers : DbContextWithTriggers, IApplicationContextContract
80-
{
81-
public ApplicationContextWithTriggers(DbContextOptions<ApplicationContextWithTriggers> options, IServiceProvider serviceProvider) : base(serviceProvider, options)
82-
{
83-
}
84-
85-
86-
protected override void OnModelCreating(ModelBuilder modelBuilder)
87-
{
88-
modelBuilder.Entity<StudentCourse>().HasKey(x => new { x.StudentId, x.CourseId });
89-
}
90-
91-
public DbSet<Student> Students { get; set; }
92-
93-
public DbSet<Course> Courses { get; set; }
94-
95-
public DbSet<StudentCourse> StudentCourses { get; set; }
96-
}
97-
9871
public class TriggeredApplicationContext : DbContext, IApplicationContextContract
9972
{
10073
public TriggeredApplicationContext(DbContextOptions<TriggeredApplicationContext> options) : base(options)
@@ -112,27 +85,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
11285

11386
public DbSet<StudentCourse> StudentCourses { get; set; }
11487
}
115-
116-
public class RamsesApplicationContext : LifecycleDbContext, IApplicationContextContract
117-
{
118-
public RamsesApplicationContext(DbContextOptions<RamsesApplicationContext> options) : base(options)
119-
{
120-
}
121-
122-
protected override void OnModelCreating(ModelBuilder modelBuilder)
123-
{
124-
modelBuilder.Entity<StudentCourse>().HasKey(x => new { x.StudentId, x.CourseId });
125-
}
126-
127-
public override int SaveChanges()
128-
{
129-
return base.SaveWithLifecycles();
130-
}
131-
132-
public DbSet<Student> Students { get; set; }
133-
134-
public DbSet<Course> Courses { get; set; }
135-
136-
public DbSet<StudentCourse> StudentCourses { get; set; }
137-
}
13888
}

benchmarks/EntityFrameworkCore.Triggered.Benchmarks/EmbracingFeaturesBenchmarks.cs

Lines changed: 0 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Linq;
33
using BenchmarkDotNet;
44
using BenchmarkDotNet.Attributes;
5-
using EntityFrameworkCore.Triggers;
65
using Microsoft.Diagnostics.Runtime.Interop;
76
using Microsoft.Diagnostics.Tracing.Analysis.GC;
87
using Microsoft.EntityFrameworkCore;
@@ -31,35 +30,8 @@ public void GlobalSetup()
3130
triggerOptions.AddTrigger<Triggers.SignStudentUpForMandatoryCourses>();
3231
});
3332
})
34-
.AddDbContext<ApplicationContextWithTriggers>(options => {
35-
options
36-
.UseInMemoryDatabase(nameof(WithDbContextWithTriggers));
37-
})
38-
.AddDbContext<RamsesApplicationContext>(options => {
39-
options
40-
.UseInMemoryDatabase(nameof(RamsesApplicationContext));
41-
})
42-
.AddTriggers()
43-
.AddSingleton(typeof(ITriggers<,>), typeof(Triggers<,>))
44-
.AddSingleton(typeof(ITriggers<>), typeof(Triggers<>))
45-
.AddSingleton(typeof(ITriggers), typeof(EntityFrameworkCore.Triggers.Triggers))
4633
.BuildServiceProvider();
4734

48-
Triggers<Student, ApplicationContextWithTriggers>.GlobalInserting.Add(entry => {
49-
entry.Entity.RegistrationDate = DateTimeOffset.Now;
50-
});
51-
52-
Triggers<Student, ApplicationContextWithTriggers>.GlobalInserting.Add(entry => {
53-
var mandatoryCourses = entry.Context.Courses.Where(x => x.IsMandatory).ToList();
54-
55-
foreach (var mandatoryCourse in mandatoryCourses)
56-
{
57-
entry.Context.StudentCourses.Add(new StudentCourse {
58-
CourseId = mandatoryCourse.Id,
59-
StudentId = entry.Entity.Id
60-
});
61-
}
62-
});
6335
}
6436

6537
[Params(50)]
@@ -129,44 +101,6 @@ public void WithDbContext()
129101
}
130102
}
131103

132-
[Benchmark]
133-
public void WithDbContextWithTriggers()
134-
{
135-
// setup
136-
{
137-
using var scope = _serviceProvider.CreateScope();
138-
using var context = scope.ServiceProvider.GetRequiredService<ApplicationContextWithTriggers>();
139-
140-
context.Database.EnsureDeleted();
141-
142-
context.Courses.Add(new Course { Id = Guid.NewGuid(), DisplayName = "Test", IsMandatory = true });
143-
context.SaveChanges();
144-
}
145-
146-
// execute
147-
for (var outerBatch = 0; outerBatch < OuterBatches; outerBatch++)
148-
{
149-
using var scope = _serviceProvider.CreateScope();
150-
using var context = scope.ServiceProvider.GetRequiredService<ApplicationContextWithTriggers>();
151-
152-
for (var innerBatch = 0; innerBatch < InnerBatches; innerBatch++)
153-
{
154-
var student = new Student { Id = Guid.NewGuid(), DisplayName = "Test" };
155-
context.Add(student);
156-
}
157-
158-
context.SaveChanges();
159-
}
160-
161-
// validate
162-
{
163-
using var scope = _serviceProvider.CreateScope();
164-
using var context = scope.ServiceProvider.GetRequiredService<ApplicationContextWithTriggers>();
165-
166-
Validate(context);
167-
}
168-
}
169-
170104
[Benchmark]
171105
public void WithTriggeredDbContext()
172106
{
@@ -205,55 +139,5 @@ public void WithTriggeredDbContext()
205139
Validate(context);
206140
}
207141
}
208-
209-
210-
[Benchmark]
211-
public void WithRamsesDbContext()
212-
{
213-
// setup
214-
{
215-
using var scope = _serviceProvider.CreateScope();
216-
using var context = scope.ServiceProvider.GetRequiredService<RamsesApplicationContext>();
217-
218-
context.Database.EnsureDeleted();
219-
220-
context.Courses.Add(new Course { Id = Guid.NewGuid(), DisplayName = "Test", IsMandatory = true });
221-
context.SaveChanges();
222-
}
223-
224-
// execute
225-
for (var outerBatch = 0; outerBatch < OuterBatches; outerBatch++)
226-
{
227-
using var scope = _serviceProvider.CreateScope();
228-
using var context = scope.ServiceProvider.GetRequiredService<RamsesApplicationContext>();
229-
230-
for (var innerBatch = 0; innerBatch < InnerBatches; innerBatch++)
231-
{
232-
var student = new Student { Id = Guid.NewGuid(), DisplayName = "Test" };
233-
234-
context.Add(student);
235-
236-
var mandatoryCourses = context.Courses.Where(x => x.IsMandatory).ToList();
237-
238-
foreach (var mandatoryCourse in mandatoryCourses)
239-
{
240-
context.StudentCourses.Add(new StudentCourse {
241-
CourseId = mandatoryCourse.Id,
242-
StudentId = student.Id
243-
});
244-
}
245-
}
246-
247-
context.SaveChanges();
248-
}
249-
250-
// validate
251-
{
252-
using var scope = _serviceProvider.CreateScope();
253-
using var context = scope.ServiceProvider.GetRequiredService<RamsesApplicationContext>();
254-
255-
Validate(context);
256-
}
257-
}
258142
}
259143
}

benchmarks/EntityFrameworkCore.Triggered.Benchmarks/EntityFrameworkCore.Triggered.Benchmarks.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@
1313
</PropertyGroup>
1414
<ItemGroup>
1515
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
16-
<PackageReference Include="EntityFrameworkCore.Triggers" Version="1.2.2" />
1716
<PackageReference Include="EntityFrameworkCore.Triggered" Version="2.2.0" />
1817
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0" />
19-
<PackageReference Include="Ramses" Version="3.0.1" />
2018
</ItemGroup>
2119

2220
</Project>

benchmarks/EntityFrameworkCore.Triggered.Benchmarks/PlainOverheadBenchmarks.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Linq;
33
using BenchmarkDotNet;
44
using BenchmarkDotNet.Attributes;
5-
using EntityFrameworkCore.Triggers;
65
using Microsoft.Diagnostics.Runtime.Interop;
76
using Microsoft.Diagnostics.Tracing.Analysis.GC;
87
using Microsoft.EntityFrameworkCore;
@@ -28,15 +27,6 @@ public void GlobalSetup()
2827
.UseInMemoryDatabase(nameof(WithTriggeredDbContext))
2928
.UseTriggers();
3029
})
31-
.AddDbContext<ApplicationContextWithTriggers>(options => {
32-
options
33-
.UseInMemoryDatabase(nameof(WithDbContextWithTriggers));
34-
})
35-
.AddDbContext<RamsesApplicationContext>(options => {
36-
options
37-
.UseInMemoryDatabase(nameof(RamsesApplicationContext));
38-
})
39-
.AddTriggers()
4030
.BuildServiceProvider();
4131
}
4232

@@ -107,23 +97,10 @@ public void WithDbContext()
10797
Execute<ApplicationContext>();
10898
}
10999

110-
[Benchmark]
111-
public void WithDbContextWithTriggers()
112-
{
113-
Execute<ApplicationContextWithTriggers>();
114-
}
115-
116100
[Benchmark]
117101
public void WithTriggeredDbContext()
118102
{
119103
Execute<TriggeredApplicationContext>();
120104
}
121-
122-
123-
[Benchmark]
124-
public void WithRamsesDbContext()
125-
{
126-
Execute<RamsesApplicationContext>();
127-
}
128105
}
129106
}

src/EntityFrameworkCore.Triggered/Internal/TriggerContextDescriptor.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
using System;
2+
using System.Buffers;
3+
using System.Collections.Concurrent;
24
using System.Collections.Generic;
35
using Microsoft.EntityFrameworkCore.ChangeTracking;
46

57
namespace EntityFrameworkCore.Triggered.Internal
68
{
79
public readonly struct TriggerContextDescriptor
810
{
9-
[ThreadStatic]
10-
static Dictionary<Type, Func<object, PropertyValues?, ChangeType, object>>? _cachedTriggerContextFactories;
11+
static readonly ConcurrentDictionary<Type, Func<object, PropertyValues?, ChangeType, object>> _cachedTriggerContextFactories = new();
1112

1213
readonly EntityEntry _entityEntry;
1314
readonly ChangeType _changeType;
@@ -37,19 +38,10 @@ public object GetTriggerContext()
3738

3839
var entityType = entityEntry.Entity.GetType();
3940

40-
if (_cachedTriggerContextFactories == null)
41-
{
42-
_cachedTriggerContextFactories = new Dictionary<Type, Func<object, PropertyValues?, ChangeType, object>>();
43-
}
44-
45-
if (!_cachedTriggerContextFactories.TryGetValue(entityType, out var triggerContextFactory))
46-
{
47-
triggerContextFactory = (Func<object, PropertyValues?, ChangeType, object>)typeof(TriggerContextFactory<>).MakeGenericType(entityType)
41+
var triggerContextFactory = _cachedTriggerContextFactories.GetOrAdd(entityType, entityType =>
42+
(Func<object, PropertyValues?, ChangeType, object>)typeof(TriggerContextFactory<>).MakeGenericType(entityType)
4843
.GetMethod(nameof(TriggerContextFactory<object>.Activate))
49-
.CreateDelegate(typeof(Func<object, PropertyValues?, ChangeType, object>));
50-
51-
_cachedTriggerContextFactories.Add(entityType, triggerContextFactory);
52-
}
44+
.CreateDelegate(typeof(Func<object, PropertyValues?, ChangeType, object>)));
5345

5446
return triggerContextFactory(entityEntry.Entity, originalValues, changeType);
5547
}

src/EntityFrameworkCore.Triggered/Internal/TriggerFactory.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Diagnostics;
45
using System.Linq;
@@ -10,6 +11,7 @@ namespace EntityFrameworkCore.Triggered.Internal
1011
{
1112
public sealed class TriggerFactory
1213
{
14+
static readonly ConcurrentDictionary<Type, Type> _instanceFactoryTypeCache = new();
1315
readonly IServiceProvider _internalServiceProvider;
1416

1517
public TriggerFactory(IServiceProvider internalServiceProvider)
@@ -30,12 +32,19 @@ public IEnumerable<object> Resolve(IServiceProvider serviceProvider, Type trigge
3032
}
3133

3234
// Alternatively, triggers may be registered with the extension configuration
33-
var triggerServiceFactories = _internalServiceProvider.GetServices(typeof(ITriggerInstanceFactory<>).MakeGenericType(triggerType)).Cast<ITriggerInstanceFactory>();
35+
var instanceFactoryType = _instanceFactoryTypeCache.GetOrAdd(triggerType,
36+
triggerType => typeof(ITriggerInstanceFactory<>).MakeGenericType(triggerType)
37+
);
38+
39+
var triggerServiceFactories = _internalServiceProvider.GetServices(instanceFactoryType);
3440
if (triggerServiceFactories.Any())
3541
{
3642
foreach (var triggerServiceFactory in triggerServiceFactories)
3743
{
38-
yield return triggerServiceFactory.Create(serviceProvider);
44+
if (triggerServiceFactory is not null)
45+
{
46+
yield return ((ITriggerInstanceFactory)triggerServiceFactory).Create(serviceProvider);
47+
}
3948
}
4049
}
4150
}

test/EntityFrameworkCore.Triggered.IntegrationTests/CascadingSoftDeletes/ApplicationDbContext.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99

1010
namespace EntityFrameworkCore.Triggered.IntegrationTests.CascadingSoftDeletes
1111
{
12-
public class ApplicationDbContext : DbContext
12+
public class ApplicationDbContext
13+
#if EFCORETRIGGERED1
14+
: TriggeredDbContext
15+
#else
16+
: DbContext
17+
#endif
1318
{
1419
readonly string _databaseName;
1520

test/EntityFrameworkCore.Triggered.IntegrationTests/CascadingSoftDeletes/CascadingSoftDeletesTestScenario.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void Scenario(ScenarioContext scenario)
2626
Assert.Equal(3, result);
2727
}
2828

29-
scenario.Fact("1. Soft delete works on the depest level", () => {
29+
scenario.Fact("1. Soft delete works on the deepest level", () => {
3030
dbContext.Remove(level2);
3131
var result = dbContext.SaveChanges();
3232

0 commit comments

Comments
 (0)