@@ -81,8 +81,8 @@ public async Task AddManyChanges(Guid clientId,
8181 repo . ClearChangeTracker ( ) ;
8282
8383 await using var transaction = await repo . BeginTransactionAsync ( ) ;
84- await repo . AddCommits ( commits ) ;
85- await UpdateSnapshots ( repo , commits . First ( ) , commits ) ;
84+ var updatedCommits = await repo . AddCommits ( commits ) ;
85+ await UpdateSnapshots ( repo , updatedCommits ) ;
8686 await ValidateCommits ( repo ) ;
8787 await transaction . CommitAsync ( ) ;
8888 }
@@ -119,8 +119,8 @@ private async Task Add(Commit commit)
119119 repo . ClearChangeTracker ( ) ;
120120
121121 await using var transaction = repo . IsInTransaction ? null : await repo . BeginTransactionAsync ( ) ;
122- await repo . AddCommit ( commit ) ;
123- await UpdateSnapshots ( repo , commit , [ commit ] ) ;
122+ var updatedCommits = await repo . AddCommit ( commit ) ;
123+ await UpdateSnapshots ( repo , updatedCommits ) ;
124124
125125 if ( AlwaysValidate ) await ValidateCommits ( repo ) ;
126126
@@ -155,9 +155,8 @@ async Task ISyncable.AddRangeFromSync(IEnumerable<Commit> commits)
155155 if ( oldestChange is null || newCommits is [ ] ) return ;
156156
157157 await using var transaction = await repo . BeginTransactionAsync ( ) ;
158- //don't save since UpdateSnapshots will also modify newCommits with hashes, so changes will be saved once that's done
159- await repo . AddCommits ( newCommits , false ) ;
160- await UpdateSnapshots ( repo , oldestChange , newCommits ) ;
158+ var updatedCommits = await repo . AddCommits ( newCommits ) ;
159+ await UpdateSnapshots ( repo , updatedCommits ) ;
161160 await ValidateCommits ( repo ) ;
162161 await transaction . CommitAsync ( ) ;
163162 }
@@ -194,13 +193,16 @@ ValueTask<bool> ISyncable.ShouldSync()
194193 return ValueTask . FromResult ( true ) ;
195194 }
196195
197- private async Task UpdateSnapshots ( CrdtRepository repo , Commit oldestAddedCommit , Commit [ ] newCommits )
196+ private async Task UpdateSnapshots ( CrdtRepository repo , SortedSet < Commit > commitsToApply )
198197 {
198+ if ( commitsToApply . Count == 0 ) return ;
199+ var oldestAddedCommit = commitsToApply . First ( ) ;
199200 await repo . DeleteStaleSnapshots ( oldestAddedCommit ) ;
200201 Dictionary < Guid , Guid ? > snapshotLookup ;
201- if ( newCommits . Length > 10 )
202+ if ( commitsToApply . Count > 10 )
202203 {
203- var entityIds = newCommits . SelectMany ( c => c . ChangeEntities . Select ( ce => ce . EntityId ) ) ;
204+ // Bulk-load relevant snapshots to minimize DB queries
205+ var entityIds = commitsToApply . SelectMany ( c => c . ChangeEntities . Select ( ce => ce . EntityId ) ) ;
204206 snapshotLookup = await repo . CurrentSnapshots ( )
205207 . Where ( s => entityIds . Contains ( s . EntityId ) )
206208 . Select ( s => new KeyValuePair < Guid , Guid ? > ( s . EntityId , s . Id ) )
@@ -212,7 +214,7 @@ private async Task UpdateSnapshots(CrdtRepository repo, Commit oldestAddedCommit
212214 }
213215
214216 var snapshotWorker = new SnapshotWorker ( snapshotLookup , repo , _crdtConfig . Value ) ;
215- await snapshotWorker . UpdateSnapshots ( oldestAddedCommit , newCommits ) ;
217+ await snapshotWorker . UpdateSnapshots ( commitsToApply ) ;
216218 }
217219
218220 private async Task ValidateCommits ( CrdtRepository repo )
@@ -240,8 +242,10 @@ public async Task RegenerateSnapshots()
240242 await using var repo = await _crdtRepositoryFactory . CreateRepository ( ) ;
241243 await repo . DeleteSnapshotsAndProjectedTables ( ) ;
242244 repo . ClearChangeTracker ( ) ;
243- var allCommits = await repo . CurrentCommits ( ) . AsNoTracking ( ) . ToArrayAsync ( ) ;
244- await UpdateSnapshots ( repo , allCommits . First ( ) , allCommits ) ;
245+ var allCommits = await repo . CurrentCommits ( )
246+ . Include ( c => c . ChangeEntities )
247+ . ToSortedSetAsync ( ) ;
248+ await UpdateSnapshots ( repo , allCommits ) ;
245249 }
246250
247251 public async Task < ObjectSnapshot > GetLatestSnapshotByObjectId ( Guid entityId )
@@ -305,7 +309,7 @@ public async Task<Dictionary<Guid, ObjectSnapshot>> GetSnapshotsAtCommit(Commit
305309 var repository = repo . GetScopedRepository ( commit ) ;
306310 var ( snapshots , pendingCommits ) = await repository . GetCurrentSnapshotsAndPendingCommits ( ) ;
307311
308- if ( pendingCommits . Length != 0 )
312+ if ( pendingCommits . Count != 0 )
309313 {
310314 snapshots = await SnapshotWorker . ApplyCommitsToSnapshots ( snapshots ,
311315 repository ,
@@ -340,8 +344,8 @@ public async Task<T> GetAtCommit<T>(Commit commit, Guid entityId)
340344 var newCommits = await repository . CurrentCommits ( )
341345 . Include ( c => c . ChangeEntities )
342346 . WhereAfter ( snapshot . Commit )
343- . ToArrayAsync ( ) ;
344- if ( newCommits . Length > 0 )
347+ . ToSortedSetAsync ( ) ;
348+ if ( newCommits . Count > 0 )
345349 {
346350 var snapshots = await SnapshotWorker . ApplyCommitsToSnapshots (
347351 new Dictionary < Guid , ObjectSnapshot > ( [
0 commit comments