Skip to content

Commit 095594a

Browse files
Copilotimnasnainaec
authored andcommitted
Add MongoDB transactions to WordRepository multi-collection operations (#4191)
1 parent 8641a67 commit 095594a

4 files changed

Lines changed: 70 additions & 12 deletions

File tree

Backend.Tests/Mocks/MongoDbContextMock.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public Task<IMongoTransaction> BeginTransaction()
1515

1616
private sealed class MongoTransactionMock : IMongoTransaction
1717
{
18+
public IClientSessionHandle Session => null!;
19+
1820
public Task CommitTransactionAsync()
1921
{
2022
return Task.CompletedTask;

Backend/Contexts/MongoDbContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ private class MongoTransactionWrapper(IClientSessionHandle session) : IMongoTran
2626
{
2727
private readonly IClientSessionHandle _session = session;
2828

29+
public IClientSessionHandle Session => _session;
30+
2931
public Task CommitTransactionAsync()
3032
{
3133
return _session.CommitTransactionAsync();

Backend/Interfaces/IMongoDbContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public interface IMongoDbContext
1212

1313
public interface IMongoTransaction : IDisposable
1414
{
15+
IClientSessionHandle Session { get; }
1516
Task CommitTransactionAsync();
1617
Task AbortTransactionAsync();
1718
}

Backend/Repositories/WordRepository.cs

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace BackendFramework.Repositories
1515
[ExcludeFromCodeCoverage]
1616
public class WordRepository(IMongoDbContext dbContext) : IWordRepository
1717
{
18+
private readonly IMongoDbContext _dbContext = dbContext;
1819
private readonly IMongoCollection<Word> _frontier = dbContext.Db.GetCollection<Word>("FrontierCollection");
1920
private readonly IMongoCollection<Word> _words = dbContext.Db.GetCollection<Word>("WordsCollection");
2021

@@ -100,9 +101,19 @@ public async Task<bool> DeleteAllWords(string projectId)
100101
var filterDef = new FilterDefinitionBuilder<Word>();
101102
var filter = filterDef.Eq(x => x.ProjectId, projectId);
102103

103-
var deleted = await _words.DeleteManyAsync(filter);
104-
await _frontier.DeleteManyAsync(filter);
105-
return deleted.DeletedCount != 0;
104+
using var transaction = await _dbContext.BeginTransaction();
105+
try
106+
{
107+
var deleted = await _words.DeleteManyAsync(transaction.Session, filter);
108+
await _frontier.DeleteManyAsync(transaction.Session, filter);
109+
await transaction.CommitTransactionAsync();
110+
return deleted.DeletedCount != 0;
111+
}
112+
catch
113+
{
114+
await transaction.AbortTransactionAsync();
115+
throw;
116+
}
106117
}
107118

108119
/// <summary> Removes all <see cref="Word"/>s from the Frontier for specified <see cref="Project"/> </summary>
@@ -146,8 +157,18 @@ public async Task<Word> Create(Word word)
146157
OtelService.StartActivityWithTag(otelTagName, "creating a word in WordsCollection and Frontier");
147158

148159
PopulateBlankWordTimes(word);
149-
await _words.InsertOneAsync(word);
150-
await AddFrontier(word);
160+
using var transaction = await _dbContext.BeginTransaction();
161+
try
162+
{
163+
await _words.InsertOneAsync(transaction.Session, word);
164+
await _frontier.InsertOneAsync(transaction.Session, word);
165+
await transaction.CommitTransactionAsync();
166+
}
167+
catch
168+
{
169+
await transaction.AbortTransactionAsync();
170+
throw;
171+
}
151172
return word;
152173
}
153174

@@ -170,8 +191,18 @@ public async Task<List<Word>> Create(List<Word> words)
170191
{
171192
PopulateBlankWordTimes(w);
172193
}
173-
await _words.InsertManyAsync(words);
174-
await AddFrontier(words);
194+
using var transaction = await _dbContext.BeginTransaction();
195+
try
196+
{
197+
await _words.InsertManyAsync(transaction.Session, words);
198+
await _frontier.InsertManyAsync(transaction.Session, words);
199+
await transaction.CommitTransactionAsync();
200+
}
201+
catch
202+
{
203+
await transaction.AbortTransactionAsync();
204+
throw;
205+
}
175206
return words;
176207
}
177208

@@ -204,9 +235,20 @@ public async Task<Word> CreateAndDeleteFrontier(Word newWord, string oldWordId)
204235
otelTagName, "creating word in WordsCollection and Frontier, deleting old word from Frontier");
205236

206237
PopulateBlankWordTimes(newWord);
207-
await _words.InsertOneAsync(newWord);
208-
await _frontier.InsertOneAsync(newWord);
209-
await _frontier.FindOneAndDeleteAsync(GetProjectWordFilter(newWord.ProjectId, oldWordId));
238+
using var transaction = await _dbContext.BeginTransaction();
239+
try
240+
{
241+
await _words.InsertOneAsync(transaction.Session, newWord);
242+
await _frontier.InsertOneAsync(transaction.Session, newWord);
243+
await _frontier.FindOneAndDeleteAsync(
244+
transaction.Session, GetProjectWordFilter(newWord.ProjectId, oldWordId));
245+
await transaction.CommitTransactionAsync();
246+
}
247+
catch
248+
{
249+
await transaction.AbortTransactionAsync();
250+
throw;
251+
}
210252
return newWord;
211253
}
212254

@@ -224,8 +266,19 @@ public async Task<Word> AddAndDeleteFrontier(Word deletedWord, string wordId)
224266
otelTagName, "adding word to WordsCollection, deleting word from Frontier");
225267

226268
PopulateBlankWordTimes(deletedWord);
227-
await _words.InsertOneAsync(deletedWord);
228-
await _frontier.FindOneAndDeleteAsync(GetProjectWordFilter(deletedWord.ProjectId, wordId));
269+
using var transaction = await _dbContext.BeginTransaction();
270+
try
271+
{
272+
await _words.InsertOneAsync(transaction.Session, deletedWord);
273+
await _frontier.FindOneAndDeleteAsync(
274+
transaction.Session, GetProjectWordFilter(deletedWord.ProjectId, wordId));
275+
await transaction.CommitTransactionAsync();
276+
}
277+
catch
278+
{
279+
await transaction.AbortTransactionAsync();
280+
throw;
281+
}
229282
return deletedWord;
230283
}
231284

0 commit comments

Comments
 (0)