You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+21-16Lines changed: 21 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,12 +13,12 @@ Triggers for EF Core. Respond to changes in your DbContext before and after they
13
13
14
14
## Getting started
15
15
1. Install the package from [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Triggered)
16
-
2.Implement Triggers by implementing `IBeforeSaveTrigger<TEntity>` and `IAfterSaveTrigger<TEntity>`
16
+
2.Write triggers by implementing `IBeforeSaveTrigger<TEntity>` and `IAfterSaveTrigger<TEntity>`
17
17
3. Register your triggers with your DbContext
18
18
4. View our [samples](https://github.com/koenbeuk/EntityFrameworkCore.Triggered/tree/master/samples) and [more samples](https://github.com/koenbeuk/EntityFrameworkCore.Triggered.Samples) and [a sample application](https://github.com/koenbeuk/EntityFrameworkCore.BookStoreSampleApp)
19
-
5. Check out our [wiki](https://github.com/koenbeuk/EntityFrameworkCore.Triggered/wiki) for tips and tricks on getting started and being succesfull.
19
+
5. Check out our [wiki](https://github.com/koenbeuk/EntityFrameworkCore.Triggered/wiki) for tips and tricks on getting started and being successful.
20
20
21
-
> Since EntityFrameworkCore.Triggered 2.0, triggers will be invoked automatically, however this requires EFCore 5.0. If you're stuck with EFCore 3.1 then you can use [EntityFrameworkCore.Triggered V1](https://www.nuget.org/packages/EntityFrameworkCore.Triggered/1.1.0). This requires you to inherit from `TriggeredDbContext` or manual management of trigger sessions.
21
+
> Since EntityFrameworkCore.Triggered 2.0, triggers will be invoked automatically, however this requires EF Core 5.0. If you're stuck with EF Core 3.1 then you can use [EntityFrameworkCore.Triggered V1](https://www.nuget.org/packages/EntityFrameworkCore.Triggered/1.1.0). This requires you to inherit from `TriggeredDbContext` or handle manual management of trigger sessions.
22
22
23
23
### Example
24
24
```csharp
@@ -97,10 +97,10 @@ public class Startup
97
97
```
98
98
99
99
### Related articles
100
-
[Triggers for Entity Framework Core](https://onthedrift.com/posts/efcore-triggered-part1/) - Introduces the idea of using EFCore triggers in your codebase
100
+
[Triggers for Entity Framework Core](https://onthedrift.com/posts/efcore-triggered-part1/) - Introduces the idea of using EF Core triggers in your codebase
101
101
102
102
### Trigger discovery
103
-
In the given example, we register triggers directly with our DbContext. This is the recommended approach starting from version 2.3 and 1.4 respectively. If you're on an older version then its recommend to register triggers with your applications DI container instead:
103
+
In the given example, we register triggers directly with our DbContext. This is the recommended approach starting from version 2.3 and 1.4 respectively. If you're on an older version then it's recommended to register triggers with your application's DI container instead:
When using DbContextPooling, Triggers need additional help in discovering the IServiceProvider that was used to obtain a Lease on the current DbContext. This library exposes an easy-to-use plugin to enable this additional complexity which requires a call to `AddTriggeredDbContextPool`.
121
+
### DbContext pooling
122
+
When using EF Core's [DbContext pooling](https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling), Triggers internally needs to discover the `IServiceProvider` that was used to obtain a lease on the current DbContext. Thankfully, all that's complexity is hidden and all that's required is a call to `AddTriggeredDbContextPool`.
123
123
124
124
```csharp
125
125
services.AddDbContextPool<ApplicationDbContext>(...); // Before
Currently there are 2 types of cascading strategies out of the box, with the support to providing your own: `NoCascade` and `EntityAndType` (default). The former simply disables cascading whereas the latter cascades triggers for as long as the combination of the Entity and the change type is unique. `EntityAndType` is the recommended and default cascading strategy.
137
+
Currently there are 2 types of cascading strategies out of the box: `NoCascade` and `EntityAndType` (default). The former simply disables cascading, whereas the latter cascades triggers for as long as the combination of the Entity and the change type is unique. `EntityAndType` is the recommended and default cascading strategy. You can also provide your own implemention.
138
138
139
139
### Inheritance
140
140
Triggers support inheritance and sort execution of these triggers based on least concrete to most concrete. Given the following example:
Triggers will be executed in that order: First those for `IAnimal`, then those for `Animal`, then those for `ICat` and finally `Cat` itself. If multiple triggers are registered for the same type then they will execute in order or registration with the DI container.
148
+
In this example, triggers will be executed in the order:
149
+
* those for `IAnimal`,
150
+
* those for `Animal`
151
+
* those for `ICat`, and finally
152
+
*`Cat` itself.
153
+
154
+
If multiple triggers are registered for the same type, they will execute in order they were registered with the DI container.
149
155
150
156
### Priorities
151
-
In addition to inheritance
152
-
and the order in which triggers are registered, a trigger can also implement the `ITriggerPriority` interface. This allows a trigger to configure a custom priority (default: 0). Triggers will then be executed in order of their priority (lower goes first). This means that a trigger for Cat can execute before a trigger for Animal, for as long as its priority is set to run earlier. A convenient set of priorities are exposed in the `CommonTriggerPriority` class
157
+
In addition to inheritance and the order in which triggers are registered, a trigger can also implement the `ITriggerPriority` interface. This allows a trigger to configure a custom priority (default: 0). Triggers will then be executed in order of their priority (lower goes first). This means that a trigger for `Cat` can execute before a trigger for `Animal`, for as long as its priority is set to run earlier. A convenient set of priorities are exposed in the `CommonTriggerPriority` class.
153
158
154
159
### Error handling
155
-
In some cases, you want to be triggered when a DbUpdateException occurs. For this purpose we have `IAfterSaveFailedTrigger<TEntity>`. This gets triggered for all entities as part of the change set when DbContext.SaveChanges raises a DbUpdateException. The handling method: `AfterSaveFailed` in turn gets called with the trigger context containing the entity as well as the exception. You may attempt to call `DbContext.SaveChanges` again from within this trigger. This will not raise triggers that are already raised and only raise triggers that have since become relevant (based on the cascading configuration).
160
+
In some cases, you want to be triggered when a `DbUpdateException` occurs. For this purpose we have `IAfterSaveFailedTrigger<TEntity>`. This gets triggered for all entities as part of the change set when DbContext.SaveChanges raises a DbUpdateException. The handling method: `AfterSaveFailed` in turn gets called with the trigger context containing the entity as well as the exception. You may attempt to call `DbContext.SaveChanges` again from within this trigger. This will not raise triggers that are already raised and only raise triggers that have since become relevant (based on the cascading configuration).
156
161
157
162
### Lifecycle triggers
158
-
Starting with version 2.1.0, we added support for Lifecycle triggers. These triggers are invoked once per trigger type per SaveChanges lifecyle and reside within the `EntityFrameworkCore.Triggered.Lifecycles` namespace. These can be used to run something before/after all individual triggers have run. Consider the following example:
163
+
Starting with version 2.1.0, we added support for "Lifecycle triggers". These triggers are invoked once per trigger type per `SaveChanges` lifecyle and reside within the `EntityFrameworkCore.Triggered.Lifecycles` namespace. These can be used to run something before/after all individual triggers have run. Consider the following example:
@@ -176,7 +181,7 @@ public BulkReportTrigger : IAfterSaveTrigger<Email>, IAfterSaveCompletedTrigger
176
181
```
177
182
178
183
### Transactions
179
-
ManydatabaseproviderssupporttheconceptofaTransaction. BydefaultwhenusingSqlServerwithEntityFrameworkCore, anycalltoSaveChangeswillbewrappedinatransaction. Anychangesmadein `IBeforeSaveTrigger<TEntity>` willbeincludedwithinthetransactionandchangesmadein `IAfterSaveTrigger<TEntity>` willnot. However, itispossiblefortheuserto [explicitlycontroltransactions](https://docs.microsoft.com/en-us/ef/core/saving/transactions). Triggers are extensible and one such extension are [Transactional Triggers](https://www.nuget.org/packages/EntityFrameworkCore.Triggered.Transactions/). In order to use this plugin you will have to implement a few steps:
184
+
ManydatabaseproviderssupporttheconceptofaTransaction. BydefaultwhenusingSqlServerwithEntityFrameworkCore, anycallto`SaveChanges`willbewrappedinatransaction. Anychangesmadein `IBeforeSaveTrigger<TEntity>` willbeincludedwithinthetransactionandchangesmadein `IAfterSaveTrigger<TEntity>` willnot. However, itispossiblefortheuserto [explicitlycontroltransactions](https://docs.microsoft.com/en-us/ef/core/saving/transactions). Triggers are extensible and one such extension are [Transactional Triggers](https://www.nuget.org/packages/EntityFrameworkCore.Triggered.Transactions/). In order to use this plugin you will have to implement a few steps:
180
185
```csharp
181
186
// OPTIONAL: Enable transactions when configuring triggers (Required ONLY when not using dependency injection)
Bydefaultweoffer3triggertypes: `IBeforeSaveTrigger`, `IAfterSaveTrigger` and `IAfterSaveFailedTrigger`. Thesewillcovermostcases. Inadditionweoffer `IRaiseBeforeCommitTrigger` and `IRaiseAfterCommitTrigger` asanextensiontofurtherenhanceyourcontrolofwhentriggersshouldrun. Wealsooffersupportforcustomtriggers. Letssaywewanttoreacttospecificeventshappeninginyourcontext. Wecandosobycreatinganewinterface: IThisThingJustHappenedTriggerandimplementinganextensionmethodforITriggerSessiontoinvoketriggersofthattype. Pleasetakealookathow [Transactionaltriggers](https://github.com/koenbeuk/EntityFrameworkCore.Triggered/tree/master/src/EntityFrameworkCore.Triggered.Transactions) are implemented as an example.
210
+
Bydefaultweoffer3triggertypes: `IBeforeSaveTrigger`, `IAfterSaveTrigger` and `IAfterSaveFailedTrigger`. Thesewillcovermostcases. Inadditionweoffer `IRaiseBeforeCommitTrigger` and `IRaiseAfterCommitTrigger` asanextensiontofurtherenhanceyourcontrolofwhentriggersshouldrun. Wealsooffersupportforcustomtriggers. Let's say we want to react to specific events happening in your context. We can do so by creating a new interface `IThisThingJustHappenedTrigger` and implementing an extension method for `ITriggerSession` to invoke triggers of that type. Please take a look at how [Transactional triggers](https://github.com/koenbeuk/EntityFrameworkCore.Triggered/tree/master/src/EntityFrameworkCore.Triggered.Transactions) are implemented as an example.
206
211
207
212
### Similar products
208
-
- [Ramses](https://github.com/JValck/Ramses): Lifecycle hooks for EFCore. A simple yet effective way of reacting to changes. Great for situations where you simply want to make sure that a property is set before saving to the database. Limited though in features as there is no dependency injection, no async support, no extensibility model and lifecycle hooks need to be implemented on the entity type itself.
213
+
- [Ramses](https://github.com/JValck/Ramses): Lifecycle hooks for EF Core. A simple yet effective way of reacting to changes. Great for situations where you simply want to make sure that a property is set before saving to the database. Limited though in features as there is no dependency injection, no async support, no extensibility model and lifecycle hooks need to be implemented on the entity type itself.
209
214
- [EntityFramework.Triggers](https://github.com/NickStrupat/EntityFramework.Triggers). Add triggers to your entities with insert, update, and delete events. There are three events for each: before, after, and upon failure. A fine alternative to EntityFrameworkCore.Triggered. It has been around for some time and has support for EF6 and boast a decent community. There are plenty of trigger types to opt into including the option to cancel SaveChanges from within a trigger. A big drawback however is that it does not support cascading triggers so that triggers can never be relied on to enforce a domain constraint.
0 commit comments