Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/Persistence/EfCoreTests/MultiTenancy/MultiTenancyCompliance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,39 @@ public async Task end_to_end_with_default_database()
}
}

[Fact]
public async Task end_to_end_with_cascading_messages()
{
var blueId = Guid.NewGuid();
var redId = Guid.NewGuid();
var greenId = Guid.NewGuid();

await theHost.InvokeMessageAndWaitAsync(new StartAndTriggerApproval(blueId, "Blue!"), "blue");
await theHost.InvokeMessageAndWaitAsync(new StartAndTriggerApproval(redId, "Red!"), "red");
await theHost.InvokeMessageAndWaitAsync(new StartAndTriggerApproval(greenId, "Green!"), "green");

var blueDbContext = await theBuilder.BuildAsync("blue", CancellationToken.None);
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);

var blue = await blueDbContext.Items.FindAsync(blueId);
blue.Name.ShouldBe("Blue!");
blue.Approved.ShouldBeTrue();
(await greenDbContext.Items.FindAsync(blueId)).ShouldBeNull();
(await redDbContext.Items.FindAsync(blueId)).ShouldBeNull();

(await blueDbContext.Items.FindAsync(redId)).ShouldBeNull();
(await greenDbContext.Items.FindAsync(redId)).ShouldBeNull();
var red = await redDbContext.Items.FindAsync(redId);
red.Name.ShouldBe("Red!");
red.Approved.ShouldBeTrue();

(await blueDbContext.Items.FindAsync(greenId)).ShouldBeNull();
var green = await greenDbContext.Items.FindAsync(greenId);
green.Name.ShouldBe("Green!");
green.Approved.ShouldBeTrue();
(await redDbContext.Items.FindAsync(greenId)).ShouldBeNull();
}

[Fact]
public async Task with_http_posts_using_storage_actions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container)
if (isMultiTenanted(container, dbContextType))
{
var createContext = typeof(CreateTenantedDbContext<>).CloseAndBuildAs<Frame>(dbContextType);

chain.Middleware.Insert(0, createContext);
chain.Middleware.Insert(0, new EnrollTenantedDbContextInTransaction(dbContextType, chain.Idempotency));
}
else
{
Expand Down Expand Up @@ -171,6 +173,7 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container, T
{
var createContext = typeof(CreateTenantedDbContext<>).CloseAndBuildAs<Frame>(dbType);
chain.Middleware.Insert(0, createContext);
chain.Middleware.Insert(0, new EnrollTenantedDbContextInTransaction(dbType, chain.Idempotency));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using JasperFx.CodeGeneration;
using JasperFx.CodeGeneration.Frames;
using JasperFx.CodeGeneration.Model;
using JasperFx.Core.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Wolverine.Persistence;
using Wolverine.Runtime;

namespace Wolverine.EntityFrameworkCore.Codegen;

internal class EnrollTenantedDbContextInTransaction : AsyncFrame
{
private readonly Type _dbContextType;
private readonly IdempotencyStyle _idempotencyStyle;

private Variable _dbContext;
private Variable _cancellation;
private Variable? _context;

public EnrollTenantedDbContextInTransaction(Type dbContextType, IdempotencyStyle idempotencyStyle)
{
_dbContextType = dbContextType;
_idempotencyStyle = idempotencyStyle;
}

public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
{
writer.Write("BLOCK:try");

// EF Core can only do eager idempotent checks
if (_idempotencyStyle == IdempotencyStyle.Eager || _idempotencyStyle == IdempotencyStyle.Optimistic)
{
writer.Write($"await {_context.Usage}.{nameof(MessageContext.AssertEagerIdempotencyAsync)}({_cancellation.Usage});");
}

writer.Write($"BLOCK:if ({_dbContext.Usage}.Database.CurrentTransaction == null)");
writer.Write($"await {_dbContext.Usage}.Database.BeginTransactionAsync({_cancellation.Usage});");
writer.FinishBlock();

Next?.GenerateCode(method, writer);

writer.Write($"await {_dbContext.Usage}.Database.CommitTransactionAsync({_cancellation.Usage});");
writer.FinishBlock();
writer.Write($"BLOCK:catch ({typeof(Exception).FullNameInCode()})");
writer.Write($"await {_dbContext.Usage}.Database.RollbackTransactionAsync({_cancellation.Usage});");
writer.Write("throw;");
writer.FinishBlock();
}

public override IEnumerable<Variable> FindVariables(IMethodVariables chain)
{
_context = chain.FindVariable(typeof(MessageContext));
yield return _context;

_dbContext = chain.FindVariable(_dbContextType);
yield return _dbContext;

_cancellation = chain.FindVariable(typeof(CancellationToken));
yield return _cancellation;
}
}
Loading