Skip to content

Commit e2fd19b

Browse files
author
fabien.menager
committed
Handle deduplication of join records
1 parent fef0db3 commit e2fd19b

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace PhenX.EntityFrameworkCore.BulkInsert.Graph;
4+
5+
/// <summary>
6+
/// Compares pairs of entity references for equality using reference equality.
7+
/// Used for deduplicating many-to-many join records.
8+
/// </summary>
9+
internal sealed class EntityPairEqualityComparer : IEqualityComparer<(object Left, object Right)>
10+
{
11+
public static readonly EntityPairEqualityComparer Instance = new();
12+
13+
private EntityPairEqualityComparer() { }
14+
15+
public bool Equals((object Left, object Right) x, (object Left, object Right) y)
16+
{
17+
return ReferenceEquals(x.Left, y.Left) && ReferenceEquals(x.Right, y.Right);
18+
}
19+
20+
public int GetHashCode((object Left, object Right) obj)
21+
{
22+
return HashCode.Combine(
23+
RuntimeHelpers.GetHashCode(obj.Left),
24+
RuntimeHelpers.GetHashCode(obj.Right)
25+
);
26+
}
27+
}
28+

src/PhenX.EntityFrameworkCore.BulkInsert/Graph/GraphBulkInsertOrchestrator.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,19 @@ private async Task<int> InsertJoinRecords(
347347
// Get entity metadata for join type
348348
var joinEntityMetadata = graphMetadata.GetEntityMetadata(joinEntityType);
349349

350-
// Create join table entries
350+
// Deduplicate join records by entity reference pairs
351+
// Use a HashSet to track which (LeftEntity, RightEntity) pairs have been processed
352+
var seenPairs = new HashSet<(object Left, object Right)>(EntityPairEqualityComparer.Instance);
351353
var joinEntities = new List<object>();
352354

353355
foreach (var record in records)
354356
{
357+
// Skip if this exact pair of entity instances has already been processed
358+
if (!seenPairs.Add((record.LeftEntity, record.RightEntity)))
359+
{
360+
continue;
361+
}
362+
355363
// Get metadata for left and right entities
356364
var leftMetadata = graphMetadata.GetEntityMetadata(record.LeftEntity.GetType());
357365
var rightMetadata = graphMetadata.GetEntityMetadata(record.RightEntity.GetType());
@@ -415,7 +423,7 @@ private async Task<int> InsertJoinRecords(
415423

416424
if (joinEntities.Count > 0)
417425
{
418-
// Insert join entities
426+
// Insert join entities (only unique ones)
419427
await InsertJoinEntities(sync, context, joinEntityType, joinEntities, options, provider, ctk);
420428
totalJoinRecordsInserted += joinEntities.Count;
421429
}

0 commit comments

Comments
 (0)