Skip to content

Commit b3ecb10

Browse files
Document Cosmos trigger execution support (#5114)
Fixes #5080 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
1 parent 5298667 commit b3ecb10

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

entity-framework/core/providers/cosmos/modeling.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Modeling - Azure Cosmos DB Provider - EF Core
33
description: Configuring the model with the Azure Cosmos DB EF Core Provider
44
author: roji
5-
ms.date: 09/19/2024
5+
ms.date: 09/26/2024
66
uid: core/providers/cosmos/modeling
77
---
88
# Configuring the model with the EF Core Azure Cosmos DB Provider
@@ -334,3 +334,25 @@ To configure an entity type to use [optimistic concurrency](xref:core/saving/con
334334
To make it easier to resolve concurrency errors you can map the eTag to a CLR property using <xref:Microsoft.EntityFrameworkCore.CosmosPropertyBuilderExtensions.IsETagConcurrency*>.
335335

336336
[!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETagProperty)]
337+
338+
## Database triggers
339+
340+
> [!NOTE]
341+
> Database trigger execution support was introduced in EF Core 10.0.
342+
343+
Azure Cosmos DB supports pre- and post-triggers that run before or after database operations. EF Core can be configured to execute these triggers when performing save operations.
344+
345+
> [!IMPORTANT]
346+
> Triggers are executed server-side by Azure Cosmos DB when EF Core performs operations, but they are not enforced - operations can be performed without running triggers if accessing the database directly. This means triggers should not be used for security-related functionality such as authentication or auditing, as they can be bypassed by applications that access the database directly without using EF Core.
347+
348+
To configure triggers on an entity type, use the `HasTrigger` method:
349+
350+
[!code-csharp[TriggerConfiguration](../../../../samples/core/Cosmos/ModelBuilding/TriggerSample.cs?name=TriggerConfiguration)]
351+
352+
The `HasTrigger` method requires:
353+
354+
* **modelName**: The name of the trigger in Azure Cosmos DB
355+
* **triggerType**: Either `TriggerType.Pre` (executed before the operation) or `TriggerType.Post` (executed after the operation)
356+
* **triggerOperation**: The operation that should execute the trigger - `Create`, `Replace`, `Delete`, or `All`
357+
358+
Before triggers can be executed, they must be created in Azure Cosmos DB using the Cosmos SDK or Azure portal. The trigger name configured in EF Core must match the trigger name in Azure Cosmos DB.

samples/core/Cosmos/Cosmos.csproj

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

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="8.0.0" />
9+
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="10.0.0-rc.1.25451.107" />
1010
</ItemGroup>
1111

1212
</Project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Microsoft.Azure.Cosmos.Scripts;
2+
using Microsoft.EntityFrameworkCore;
3+
using System.Threading.Tasks;
4+
5+
namespace Cosmos.ModelBuilding;
6+
7+
public static class TriggerSample
8+
{
9+
public static async Task ConfigureTriggers()
10+
{
11+
var contextOptions = new DbContextOptionsBuilder<TriggerContext>()
12+
.UseCosmos("https://localhost:8081", "account-key", "sample");
13+
14+
using var context = new TriggerContext(contextOptions.Options);
15+
16+
// Ensure database is created
17+
await context.Database.EnsureCreatedAsync();
18+
19+
// Create a new product - this will trigger the PreInsertTrigger
20+
var product = new Product
21+
{
22+
Id = 1,
23+
Name = "Sample Product",
24+
Price = 19.99m,
25+
Category = "Electronics"
26+
};
27+
28+
context.Products.Add(product);
29+
await context.SaveChangesAsync();
30+
31+
// Update the product - this will trigger the UpdateTrigger
32+
product.Price = 24.99m;
33+
await context.SaveChangesAsync();
34+
35+
// Delete the product - this will trigger the PostDeleteTrigger
36+
context.Products.Remove(product);
37+
await context.SaveChangesAsync();
38+
}
39+
}
40+
41+
public class TriggerContext : DbContext
42+
{
43+
public TriggerContext(DbContextOptions options) : base(options) { }
44+
45+
public DbSet<Product> Products { get; set; }
46+
47+
protected override void OnModelCreating(ModelBuilder modelBuilder)
48+
{
49+
modelBuilder.Entity<Product>(entity =>
50+
{
51+
entity.HasPartitionKey(p => p.Category);
52+
53+
#region TriggerConfiguration
54+
// Configure pre-trigger for create operations
55+
entity.HasTrigger("PreInsertTrigger", TriggerType.Pre, TriggerOperation.Create);
56+
57+
// Configure post-trigger for delete operations
58+
entity.HasTrigger("PostDeleteTrigger", TriggerType.Post, TriggerOperation.Delete);
59+
60+
// Configure trigger for replace operations
61+
entity.HasTrigger("UpdateTrigger", TriggerType.Pre, TriggerOperation.Replace);
62+
#endregion
63+
});
64+
}
65+
}
66+
67+
public class Product
68+
{
69+
public int Id { get; set; }
70+
public string Name { get; set; } = null!;
71+
public decimal Price { get; set; }
72+
public string Category { get; set; } = null!;
73+
}

samples/global.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"sdk": {
3+
"version": "10.0.100-rc.1.25451.107"
4+
}
5+
}

0 commit comments

Comments
 (0)