Skip to content

Commit 02749da

Browse files
committed
Early implementation of the trigger context Bag property
1 parent 1998396 commit 02749da

7 files changed

Lines changed: 59 additions & 27 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace EntityFrameworkCore.Triggered.Internal
6+
{
7+
public sealed class EntityBagStateManager
8+
{
9+
private readonly Dictionary<object, IDictionary<string, object>> _resolvedBags = new();
10+
11+
public IDictionary<string, object> GetForEntity(object entity)
12+
{
13+
if (!_resolvedBags.TryGetValue(entity, out var bag))
14+
{
15+
bag = new Dictionary<string, object>();
16+
_resolvedBags.Add(entity, bag);
17+
}
18+
19+
return bag;
20+
}
21+
}
22+
}

src/EntityFrameworkCore.Triggered/Internal/TriggerContextDescriptor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace EntityFrameworkCore.Triggered.Internal
66
{
77
public readonly struct TriggerContextDescriptor
88
{
9-
static readonly ConcurrentDictionary<Type, Func<object, PropertyValues?, ChangeType, object>> _cachedTriggerContextFactories = new();
9+
static readonly ConcurrentDictionary<Type, Func<object, PropertyValues?, ChangeType, EntityBagStateManager, object>> _cachedTriggerContextFactories = new();
1010

1111
readonly EntityEntry _entityEntry;
1212
readonly ChangeType _changeType;
@@ -23,7 +23,7 @@ public TriggerContextDescriptor(EntityEntry entityEntry, ChangeType changeType)
2323
public object Entity => _entityEntry!.Entity;
2424
public Type EntityType => _entityEntry!.Entity.GetType();
2525

26-
public object GetTriggerContext()
26+
public object GetTriggerContext(EntityBagStateManager entityBagStateManager)
2727
{
2828
var entityEntry = _entityEntry;
2929
var changeType = _changeType;
@@ -37,11 +37,11 @@ public object GetTriggerContext()
3737
var entityType = entityEntry.Entity.GetType();
3838

3939
var triggerContextFactory = _cachedTriggerContextFactories.GetOrAdd(entityType, entityType =>
40-
(Func<object, PropertyValues?, ChangeType, object>)typeof(TriggerContextFactory<>).MakeGenericType(entityType)
40+
(Func<object, PropertyValues?, ChangeType, EntityBagStateManager, object >)typeof(TriggerContextFactory<>).MakeGenericType(entityType)
4141
.GetMethod(nameof(TriggerContextFactory<object>.Activate))
42-
.CreateDelegate(typeof(Func<object, PropertyValues?, ChangeType, object>)));
42+
.CreateDelegate(typeof(Func<object, PropertyValues?, ChangeType, EntityBagStateManager, object>)));
4343

44-
return triggerContextFactory(entityEntry.Entity, originalValues, changeType);
44+
return triggerContextFactory(entityEntry.Entity, originalValues, changeType, entityBagStateManager);
4545
}
4646
}
4747
}

src/EntityFrameworkCore.Triggered/Internal/TriggerContextFactory.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,32 @@ namespace EntityFrameworkCore.Triggered.Internal
77
public static class TriggerContextFactory<TEntityType>
88
where TEntityType : class
99
{
10-
readonly static Func<object, PropertyValues?, ChangeType, TriggerContext<TEntityType>> _factoryMethod = CreateFactoryMethod();
10+
readonly static Func<object, PropertyValues?, ChangeType, EntityBagStateManager, TriggerContext<TEntityType>> _factoryMethod = CreateFactoryMethod();
1111

12-
static Func<object, PropertyValues?, ChangeType, TriggerContext<TEntityType>> CreateFactoryMethod()
12+
static Func<object, PropertyValues?, ChangeType, EntityBagStateManager, TriggerContext<TEntityType>> CreateFactoryMethod()
1313
{
1414
var entityParamExpression = Expression.Parameter(typeof(object), "object");
1515
var originalValuesParamExpression = Expression.Parameter(typeof(PropertyValues), "originalValues");
1616
var changeTypeParamExpression = Expression.Parameter(typeof(ChangeType), "changeType");
17+
var entityBagStateManagerExpression = Expression.Parameter(typeof(EntityBagStateManager), "entityBagStateManager");
1718

18-
return Expression.Lambda<Func<object, PropertyValues?, ChangeType, TriggerContext<TEntityType>>>(
19+
return Expression.Lambda<Func<object, PropertyValues?, ChangeType, EntityBagStateManager, TriggerContext<TEntityType>>>(
1920
Expression.New(
20-
typeof(TriggerContext<>).MakeGenericType(typeof(TEntityType)).GetConstructor(new[] { typeof(object), typeof(PropertyValues), typeof(ChangeType) }),
21+
typeof(TriggerContext<>).MakeGenericType(typeof(TEntityType)).GetConstructor(new[] { typeof(object), typeof(PropertyValues), typeof(ChangeType), typeof(EntityBagStateManager) }),
2122
entityParamExpression,
2223
originalValuesParamExpression,
23-
changeTypeParamExpression
24+
changeTypeParamExpression,
25+
entityBagStateManagerExpression
2426
),
2527
entityParamExpression,
2628
originalValuesParamExpression,
27-
changeTypeParamExpression
29+
changeTypeParamExpression,
30+
entityBagStateManagerExpression
2831
)
2932
.Compile();
3033
}
3134

32-
public static object Activate(object entity, PropertyValues? originalValues, ChangeType changeType)
33-
=> _factoryMethod(entity, originalValues, changeType);
35+
public static object Activate(object entity, PropertyValues? originalValues, ChangeType changeType, EntityBagStateManager entityBagStateManager)
36+
=> _factoryMethod(entity, originalValues, changeType, entityBagStateManager);
3437
}
3538
}

src/EntityFrameworkCore.Triggered/TriggerContext.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
using Microsoft.EntityFrameworkCore.ChangeTracking;
1+
using System.Collections.Generic;
2+
using EntityFrameworkCore.Triggered.Internal;
3+
using Microsoft.EntityFrameworkCore.ChangeTracking;
24

35
namespace EntityFrameworkCore.Triggered
46
{
57
public class TriggerContext<TEntity> : ITriggerContext<TEntity>
68
where TEntity : class
79
{
8-
readonly ChangeType _type;
910
readonly TEntity _entity;
11+
readonly ChangeType _type;
1012
readonly PropertyValues? _originalValues;
13+
readonly EntityBagStateManager _entityBagStateManager;
1114

1215
TEntity? _unmodifiedEntity;
1316

14-
15-
public TriggerContext(object entity, PropertyValues? originalValues, ChangeType changeType)
17+
public TriggerContext(object entity, PropertyValues? originalValues, ChangeType changeType, EntityBagStateManager entityBagStateManager)
1618
{
17-
_type = changeType;
1819
_entity = (TEntity)entity;
1920
_originalValues = originalValues;
21+
_type = changeType;
22+
_entityBagStateManager = entityBagStateManager;
2023
}
2124

2225
public ChangeType ChangeType => _type;
@@ -40,5 +43,7 @@ public TEntity? UnmodifiedEntity
4043
}
4144
}
4245
}
46+
47+
public IDictionary<string, object> Bag => _entityBagStateManager.GetForEntity(_entity);
4348
}
4449
}

src/EntityFrameworkCore.Triggered/TriggerSession.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class TriggerSession : ITriggerSession
2222
readonly TriggerContextTracker _tracker;
2323
readonly ILogger<TriggerSession> _logger;
2424

25+
readonly EntityBagStateManager _entityBagStateManager = new();
26+
2527
bool _raiseBeforeSaveTriggersCalled;
2628

2729
public TriggerSession(ITriggerService triggerService, TriggerOptions options, ITriggerDiscoveryService triggerDiscoveryService, TriggerContextTracker tracker, ILogger<TriggerSession> logger)
@@ -86,7 +88,7 @@ public async Task RaiseTriggers(Type openTriggerType, Exception? exception, ITri
8688
_logger.LogInformation("Invoking trigger: {trigger} as {triggerType}", triggerDescriptor.Trigger.GetType(), triggerDescriptor.TypeDescriptor.TriggerType);
8789
}
8890

89-
await triggerDescriptor.Invoke(triggerContextDescriptor.GetTriggerContext(), exception, cancellationToken).ConfigureAwait(false);
91+
await triggerDescriptor.Invoke(triggerContextDescriptor.GetTriggerContext(_entityBagStateManager), exception, cancellationToken).ConfigureAwait(false);
9092
}
9193
}
9294

test/EntityFrameworkCore.Triggered.Tests/Internal/TriggerContextFactoryTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void Activate_ReturnsInstance()
3535
using var dbContext = new TestDbContext();
3636
var entityEntry = dbContext.Entry(new TestModel { });
3737

38-
var result = TriggerContextFactory<object>.Activate(entityEntry, entityEntry.OriginalValues, ChangeType.Added);
38+
var result = TriggerContextFactory<object>.Activate(entityEntry, entityEntry.OriginalValues, ChangeType.Added, new());
3939

4040
Assert.NotNull(result);
4141
}

test/EntityFrameworkCore.Triggered.Tests/TriggerContextTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void UnmodifiedEntity_WhenTypeAdded_IsEmpty()
2727
{
2828
using var dbContext = new TestDbContext();
2929
var sample1 = new TestModel() { Id = 1 };
30-
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Added);
30+
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Added, new());
3131

3232
Assert.Null(subject.UnmodifiedEntity);
3333
}
@@ -37,7 +37,7 @@ public void UnmodifiedEntity_WhenTypeDeleted_IsNotEmpty()
3737
{
3838
using var dbContext = new TestDbContext();
3939
var sample1 = new TestModel();
40-
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Deleted);
40+
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Deleted, new());
4141

4242
Assert.NotNull(subject.UnmodifiedEntity);
4343
}
@@ -47,7 +47,7 @@ public void UnmodifiedEntity_WhenTypeModified_IsNotEmpty()
4747
{
4848
using var dbContext = new TestDbContext();
4949
var sample1 = new TestModel();
50-
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified);
50+
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified, new());
5151

5252
Assert.NotNull(subject.UnmodifiedEntity);
5353
}
@@ -60,7 +60,7 @@ public void UnmodifiedEntity_WhenTypeModified_HoldsUnmodifiedStateBeforeSaveChan
6060
dbContext.Add(sample1);
6161
dbContext.SaveChanges();
6262

63-
var subject = new TriggerContext<TestModel>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified);
63+
var subject = new TriggerContext<TestModel>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified, new());
6464
sample1.Name = "test2";
6565

6666
Assert.NotNull(subject.UnmodifiedEntity);
@@ -77,7 +77,7 @@ public void UnmodifiedEntity_WhenTypeModified_HoldsUnmodifiedStateAfterSaveChang
7777
dbContext.Add(sample1);
7878
dbContext.SaveChanges();
7979

80-
var subject = new TriggerContext<TestModel>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues.Clone(), ChangeType.Modified);
80+
var subject = new TriggerContext<TestModel>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues.Clone(), ChangeType.Modified, new());
8181
sample1.Name = "test2";
8282

8383
dbContext.SaveChanges();
@@ -91,7 +91,7 @@ public void Entity_IsNeverEmpty()
9191
{
9292
using var dbContext = new TestDbContext();
9393
var sample1 = new TestModel();
94-
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, default);
94+
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, default, new());
9595

9696
Assert.NotNull(subject.Entity);
9797
}
@@ -101,7 +101,7 @@ public void Type_IsNotEmpty()
101101
{
102102
using var dbContext = new TestDbContext();
103103
var sample1 = new TestModel();
104-
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified);
104+
var subject = new TriggerContext<object>(dbContext.Entry(sample1).Entity, dbContext.Entry(sample1).OriginalValues, ChangeType.Modified, new());
105105

106106
Assert.Equal(ChangeType.Modified, subject.ChangeType);
107107
}

0 commit comments

Comments
 (0)