File tree Expand file tree Collapse file tree
Wolverine.EntityFrameworkCore/Internals Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -193,6 +193,37 @@ public void outbox_for_db_context_mapped()
193193 . DbContext . ShouldBeSameAs ( context ) ;
194194 }
195195
196+ [ Fact ]
197+ public async Task persisting_against_mapped_dbcontext_does_not_start_an_explicit_transaction ( )
198+ {
199+ await Host . ResetResourceState ( ) ;
200+
201+ var envelope = new Envelope
202+ {
203+ Data = [ 1 , 2 , 3 , 4 ] ,
204+ OwnerId = 5 ,
205+ Destination = TransportConstants . RepliesUri ,
206+ MessageType = "foo" ,
207+ ContentType = EnvelopeConstants . JsonContentType ,
208+ Status = EnvelopeStatus . Scheduled ,
209+ ScheduledTime = DateTimeOffset . UtcNow . AddMinutes ( 1 )
210+ } ;
211+
212+ using var nested = Host . Services . CreateScope ( ) ;
213+ var messaging = nested . ServiceProvider . GetRequiredService < IDbContextOutbox < SampleMappedDbContext > > ( )
214+ . ShouldBeOfType < DbContextOutbox < SampleMappedDbContext > > ( ) ;
215+
216+ // Regression for #3121 -- scheduling/incoming persistence against a Wolverine-mapped
217+ // DbContext must NOT begin an explicit EF Core transaction. SaveChanges provides its
218+ // own implicit transaction, and the outgoing path already behaves this way.
219+ await messaging . Transaction ! . PersistIncomingAsync ( envelope ) ;
220+ messaging . DbContext . Database . CurrentTransaction . ShouldBeNull ( ) ;
221+
222+ // Symmetry check: the outgoing path likewise leaves the transaction alone
223+ await messaging . Transaction ! . PersistOutgoingAsync ( envelope ) ;
224+ messaging . DbContext . Database . CurrentTransaction . ShouldBeNull ( ) ;
225+ }
226+
196227 [ Fact ]
197228 public async Task persist_an_outgoing_envelope_raw ( )
198229 {
Original file line number Diff line number Diff line change @@ -98,17 +98,27 @@ public async Task PersistOutgoingAsync(Envelope[] envelopes)
9898
9999 public async Task PersistIncomingAsync ( Envelope envelope )
100100 {
101- if ( DbContext . Database . CurrentTransaction == null )
102- {
103- await DbContext . Database . BeginTransactionAsync ( ) ;
104- }
105-
106101 if ( DbContext . IsWolverineEnabled ( ) )
107102 {
103+ // For a Wolverine-mapped DbContext the envelope is just tracked and flushed by
104+ // SaveChangesAsync, so don't force an explicit transaction here. We defer to whatever
105+ // the ambient transaction mode established: in Eager middleware mode a transaction was
106+ // already begun (EnrollDbContextInTransaction / StartDatabaseTransactionForDbContext) and
107+ // the tracked entity enrolls into it at SaveChanges; in Lightweight/lazy mode there is no
108+ // transaction and SaveChanges provides its own implicit one. This mirrors
109+ // PersistOutgoingAsync and keeps ScheduleAsync from starting a transaction the caller
110+ // never asked for (see #3121).
108111 DbContext . Add ( new IncomingMessage ( envelope ) ) ;
109112 }
110113 else
111114 {
115+ // The raw branch issues an ADO command that has to share the caller's transaction, so
116+ // here we do need an explicit one when none is already in flight.
117+ if ( DbContext . Database . CurrentTransaction == null )
118+ {
119+ await DbContext . Database . BeginTransactionAsync ( ) ;
120+ }
121+
112122 var conn = DbContext . Database . GetDbConnection ( ) ;
113123 var tx = DbContext . Database . CurrentTransaction ! . GetDbTransaction ( ) ;
114124 var builder = _database . ToCommandBuilder ( ) ;
You can’t perform that action at this time.
0 commit comments