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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using PhenX.EntityFrameworkCore.BulkInsert.Enums;
using PhenX.EntityFrameworkCore.BulkInsert.Extensions;
using PhenX.EntityFrameworkCore.BulkInsert.MySql;
using PhenX.EntityFrameworkCore.BulkInsert.Options;
using PhenX.EntityFrameworkCore.BulkInsert.SqlServer;
using PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContainer;
using PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
Expand Down Expand Up @@ -45,7 +44,7 @@ public async Task InsertsEntities(InsertStrategy strategy)

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableTheory]
Expand All @@ -64,7 +63,7 @@ public async Task InsertEntities_WithJson(InsertStrategy strategy)

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntityWithJson e) => e.Id));
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableFact]
Expand All @@ -90,100 +89,7 @@ public async Task InsertEntities_AndReturn_AsyncEnumerable()

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
}

[SkippableTheory]
[CombinatorialData]
public async Task InsertEntities_MultipleTimes(InsertStrategy strategy)
{
Skip.If(_context.IsProvider(ProviderType.PostgreSql));
Skip.If(_context.IsProvider(ProviderType.SqlServer));

// Arrange
var entities = new List<TestEntity>
{
new TestEntity { TestRun = _run, Name = $"{_run}_Entity1" },
new TestEntity { TestRun = _run, Name = $"{_run}_Entity2" }
};

// Act
await _context.InsertWithStrategyAsync(strategy, entities);

foreach (var entity in entities)
{
entity.NumericEnumValue = NumericEnum.Second;
}

var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities,
onConflict: new OnConflictOptions<TestEntity>
{
Update = e => e,
});

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
}

[SkippableTheory]
[CombinatorialData]
public async Task InsertEntities_MultipleTimes_WithGuidId(InsertStrategy strategy)
{
// Arrange
var entities = new List<TestEntityWithGuidId>
{
new TestEntityWithGuidId { Id = Guid.NewGuid(), Name = $"{_run}_Entity1" },
new TestEntityWithGuidId { Id = Guid.NewGuid(), Name = $"{_run}_Entity2" }
};

// Act
await _context.ExecuteBulkInsertAsync(entities);

foreach (var entity in entities)
{
entity.Name = $"Updated_{entity.Name}";
}

var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities,
onConflict: new OnConflictOptions<TestEntityWithGuidId>
{
Update = e => e,
});

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntityWithGuidId e) => e.Id));
}

[SkippableTheory]
[CombinatorialData]
public async Task InsertEntities_MultipleTimes_With_Conflict_On_Id(InsertStrategy strategy)
{
// Arrange
var entities = new List<TestEntity>
{
new TestEntity { Name = $"{_run}_Entity1" },
new TestEntity { Name = $"{_run}_Entity2" }
};

// Act
var insertedEntities0 = await _context.InsertWithStrategyAsync(strategy, entities);
foreach (var entity in insertedEntities0)
{
entity.Name = $"Updated_{entity.Name}";
}

var insertedEntities1 = await _context.InsertWithStrategyAsync(strategy, insertedEntities0,
o => o.CopyGeneratedColumns = true,
onConflict: new OnConflictOptions<TestEntity>
{
Update = e => e,
});

// Assert
insertedEntities1.Should().BeEquivalentTo(insertedEntities0,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableTheory]
Expand All @@ -205,149 +111,7 @@ public async Task InsertEntities_MoveRows(InsertStrategy strategy)

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
}

[SkippableTheory]
[InlineData(InsertStrategy.InsertReturn)]
[InlineData(InsertStrategy.InsertReturnAsync)]
public async Task InsertEntities_WithConflict_SingleColumn(InsertStrategy strategy)
{
Skip.If(_context.IsProvider(ProviderType.MySql));

// Arrange
_context.TestEntities.Add(new TestEntity { Name = $"{_run}_Entity1" });
_context.SaveChanges();
_context.ChangeTracker.Clear();

var entities = new List<TestEntity>
{
new TestEntity { Name = $"{_run}_Entity1" },
new TestEntity { TestRun = _run, Name = $"{_run}_Entity2" },
};

// Act
var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities, o =>
{
o.MoveRows = true;
}, new OnConflictOptions<TestEntity>
{
Match = e => new
{
e.Name,
},
Update = e => new TestEntity
{
Name = e.Name + " - Conflict",
},
});

// Assert
Assert.Equal(2, insertedEntities.Count);
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity1 - Conflict");
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity2");
}

[SkippableTheory]
[InlineData(InsertStrategy.Insert)]
[InlineData(InsertStrategy.InsertAsync)]
public async Task InsertEntities_WithConflict_DoNothing(InsertStrategy strategy)
{
Skip.If(_context.IsProvider(ProviderType.MySql));

// Arrange
_context.TestEntities.Add(new TestEntity { TestRun = _run, Name = $"{_run}_Entity1" });
_context.SaveChanges();
_context.ChangeTracker.Clear();

var entities = new List<TestEntity>
{
new TestEntity { TestRun = _run, Name = $"{_run}_Entity1" },
new TestEntity { TestRun = _run, Name = $"{_run}_Entity2" },
};

// Act
var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities, o =>
{
o.MoveRows = true;
}, new OnConflictOptions<TestEntity>
{
Match = e => new { e.Name }
});

// Assert
Assert.Equal(2, insertedEntities.Count);
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity1");
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity2");
}

[SkippableTheory]
[InlineData(InsertStrategy.InsertReturn)]
[InlineData(InsertStrategy.InsertReturnAsync)]
public async Task InsertEntities_WithConflict_Condition(InsertStrategy strategy)
{
Skip.If(_context.IsProvider(ProviderType.MySql));

// Arrange
_context.TestEntities.Add(new TestEntity { TestRun = _run, Name = $"{_run}_Entity1", Price = 10 });
_context.SaveChanges();
_context.ChangeTracker.Clear();

var entities = new List<TestEntity>
{
new TestEntity { TestRun = _run, Name = $"{_run}_Entity1", Price = 20 },
new TestEntity { TestRun = _run, Name = $"{_run}_Entity2", Price = 30 },
};

// Act
var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities, o =>
{
o.MoveRows = true;
}, new OnConflictOptions<TestEntity>
{
Match = e => new { e.Name },
Update = e => new TestEntity { Price = e.Price },
Condition = "EXCLUDED.some_price > test_entity.some_price"
});

// Assert
Assert.Equal(2, insertedEntities.Count);
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity1" && e.Price == 20);
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity2" && e.Price == 30);
}

[SkippableTheory]
[InlineData(InsertStrategy.InsertReturn)]
[InlineData(InsertStrategy.InsertReturnAsync)]
public async Task InsertEntities_WithConflict_MultipleColumns(InsertStrategy strategy)
{
Skip.If(_context.IsProvider(ProviderType.MySql));

// Arrange
_context.TestEntities.Add(new TestEntity { TestRun = _run, Name = $"{_run}_Entity1", Price = 10 });
_context.SaveChanges();
_context.ChangeTracker.Clear();

var entities = new List<TestEntity>
{
new TestEntity { TestRun = _run, Name = $"{_run}_Entity1", Price = 20, Identifier = Guid.NewGuid() },
new TestEntity { TestRun = _run, Name = $"{_run}_Entity2", Price = 30, Identifier = Guid.NewGuid() },
};

// Act
var insertedEntities = await _context.InsertWithStrategyAsync(strategy, entities, o =>
{
o.MoveRows = true;
}, new OnConflictOptions<TestEntity>
{
Match = e => new { e.Name },
Update = e => new TestEntity { Name = e.Name + " - Conflict", Price = 0 }
});

// Assert
Assert.Equal(2, insertedEntities.Count);
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity2");
Assert.Contains(insertedEntities, e => e.Name == $"{_run}_Entity1 - Conflict" && e.Price == 0);
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableTheory]
Expand All @@ -370,7 +134,7 @@ public async Task InsertEntities_DoesNothing_WhenEntitiesAreEmpty(InsertStrategy
public async Task InsertEntities_Many(InsertStrategy strategy)
{
// Arrange
const int count = 156055;
const int count = 56055;

var entities = Enumerable.Range(1, count).Select(i => new TestEntity
{
Expand Down Expand Up @@ -411,7 +175,7 @@ public async Task InsertEntities_AndReturn_WithEntityWithValueConverters(InsertS

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntityWithConverters e) => e.Id));
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableTheory]
Expand All @@ -432,7 +196,7 @@ public async Task InsertEntities_WithOpenTransaction_CommitsSuccessfully(InsertS

// Assert
insertedEntities.Should().BeEquivalentTo(entities,
o => o.RespectingRuntimeTypes().Excluding((TestEntity e) => e.Id));
o => o.RespectingRuntimeTypes().Excluding(e => e.Id));
}

[SkippableTheory]
Expand All @@ -456,7 +220,7 @@ public async Task InsertEntities_WithOpenTransaction_RollsBackOnFailure(InsertSt
var insertedEntities = _context.TestEntities.Where(x => x.TestRun == _run).ToList();
Assert.Empty(insertedEntities);
}

[SkippableFact]
public async Task ThrowsWhenUsingWrongConfigurationType()
{
Expand All @@ -474,23 +238,23 @@ public async Task ThrowsWhenUsingWrongConfigurationType()
if (_context.IsProvider(ProviderType.SqlServer))
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _context.ExecuteBulkInsertAsync(entities, (MySqlBulkInsertOptions o) =>
await _context.ExecuteBulkInsertAsync(entities, (MySqlBulkInsertOptions _) =>
{
}));
}

if (_context.IsProvider(ProviderType.MySql))
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _context.ExecuteBulkInsertAsync(entities, (SqlServerBulkInsertOptions o) =>
await _context.ExecuteBulkInsertAsync(entities, (SqlServerBulkInsertOptions _) =>
{
}));
}

if (_context.IsProvider(ProviderType.PostgreSql))
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _context.ExecuteBulkInsertAsync(entities, (SqlServerBulkInsertOptions o) =>
await _context.ExecuteBulkInsertAsync(entities, (SqlServerBulkInsertOptions _) =>
{
}));
}
Expand Down
Loading