I have an application that use EF Core 5 with SQL Server for production/dev and SQLLite for integration tests.
In SQL server all works perfectly but with SQLLite in my test my entity is not updated.
Let's go with some code and explanation.
Model Buidler
Here my model builder configuration for my entity :
modelBuilder.Entity<Order>(order =>
{
order.ToTable("Orders");
order.HasKey(s => s.Id);
order.Property(i => i.ConcurrencyStamp).IsRowVersion();
order.Property(i => i.ShippingExcludingTaxes).HasColumnType("decimal(10,2)");
order.Property(i => i.ShippingIncludingTaxes).HasColumnType("decimal(10,2)");
order.HasMany(s => s.OrderItems).WithOne()
.Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);
order.Metadata.FindNavigation(nameof(Order.OrderItems)).SetPropertyAccessMode(PropertyAccessMode.Field);
order.HasOne<Payment>(p => p.Payment)
.WithOne()
.HasForeignKey<Order>(p => p.PaymentId);
order.HasOne<Address>(s => s.ShippingAddress)
.WithOne()
.HasForeignKey<Order>(p => p.ShippingAddressId);
order.OwnsOne(lc => lc.Contact);
});
I already read that RowVersion does not work like in SQLServer, here I use a string generated by a Guid and here the code to update it in each savechanges ( classic & async ):
private void UpdateLastUpdate()
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is Entity && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
((Entity)entityEntry.Entity).LastUpdate = DateTime.Now;
((Entity)entityEntry.Entity).ConcurrencyStamp = Guid.NewGuid().ToString();
}
}
Domain class & Tested method
Here is my entity that I want to update
public class Order : Entity, IAggregateRoot
{
public string UserId { get; set; }
public decimal ShippingIncludingTaxes { get; set; }
public decimal ShippingExcludingTaxes { get; set; }
public OrderState State { get; set; }
public string PaymentId { get; set; }
public Payment Payment{ get; set; }
private readonly List<OrderItem> _orderItems = new List<OrderItem>();
public IReadOnlyCollection<OrderItem> OrderItems => _orderItems;
public string ShippingAddressId { get; set; }
public Address ShippingAddress { get; set; }
public OrderContact Contact { get; set; }
public ICollection<OrderHistory> OrderHistories { get; set; }
public decimal TotalIncludingTaxes => _orderItems.Sum(s => s.TotalIncludingTaxes) + ShippingIncludingTaxes;
//some other stuff
}
and the attributes that I am updating In my test
//method is in Order.cs
public void SetInProgress(OrderHistory history)
{
State = OrderState.InProgress;
OrderHistories = OrderHistories ?? new List<OrderHistory>();
OrderHistories.Add(history);
}
Test and assert
So I run my integration test, all works and I see that my DBContext take my changes.
But when It comes to make the assert, the entity is the same before the test
public class OrderControllerTest : IClassFixture<IntegrationTestFixture>
{
private readonly IntegrationTestFixture _fixture;
public OrderControllerTest(IntegrationTestFixture fixture)
{
_fixture = fixture;
Init().GetAwaiter().GetResult();
}
private IRepository<OrderHistory, UserContext> _orderHistoryRepository;
private IRepository<Nursery, PlantContext> _nurseryRepository;
private IRepository<Order, UserContext> _orderRepository;
private Nursery nursery;
private async Task Init()
{
_orderHistoryRepository = _fixture.Services.GetService<IRepository<OrderHistory, UserContext>>();
_nurseryRepository = _fixture.Services.GetService<IRepository<Nursery, PlantContext>>();
_orderRepository = _fixture.Services.GetService<IRepository<Order, UserContext>>();
nursery = await _nurseryRepository.FindAsync(a => a.LegalNumber == NurseryService.LEPAGE_LEGALNUMBER);
}
[Fact]
[Trait("Category", "Integration")]
public async Task OrderController_SendOrders_ShouldBeOkWithOrders()
{
await _orderRepository.AddAsync(OrderGenerator.GenerateOrder(OrderState.Validated, nursery.Id));
var result = await _fixture.GetAsync("api/order/send");
result.IsSuccessStatusCode.Should().BeTrue();
var histories = await _orderHistoryRepository.FilterAsync(s => true);
var orders = await _orderRepository.FilterAsync(s => true);
histories.Should().NotBeEmpty();
orders.All(all => all.State == OrderState.InProgress).Should().BeTrue();
}
}
Here when I test if my orders have InProgress state, the result is false because the State is Validated ( the state does not change since the creation ).
If somebody have an idea ? If the error occurred because of the Guid row version, if any configuration exist to make my test working ?