Reputation: 11
I have the following code in my UserRepository
:
public async Task RegisterUser(UserAggregate userAggregate)
{
try
{
await _context.UserAggregates.AddAsync(userAggregate);
await _shoppingCartRepository.CreateShoppingCart(userAggregate.UserAggregateId);
await _unitOfWork.Commit();
}
catch (Exception)
{
await _unitOfWork.Rollback();
throw;
}
}
While in the ShoppingCartRepository
, I have pretty standard code:
public async Task CreateShoppingCart(int userAggregateId)
{
var shoppingCart = new ShoppingCart
{
UserAggregateId = userAggregateId,
OrderItems = Utils.Serializer(new List<OrderItem>())
};
await _context.ShoppingCarts.AddAsync(shoppingCart);
}
Here is my "Unit of Work" implementation:
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public UnitOfWork(AppDbContext context)
{
_context = context;
}
public async Task<bool> Commit()
{
return await _context.SaveChangesAsync() > 0;
}
public Task Rollback()
{
return Task.CompletedTask;
}
}
The problem is:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
MySqlConnector.MySqlException (0x80004005): Cannot add or update a child row: a foreign key constraint fails (
bytestore
.shoppingcarts
, CONSTRAINTFK_ShoppingCarts_Use rAggregates_UserAggregateId
FOREIGN KEY (UserAggregateId
) REFERENCESuseraggregates
(Id
) ON DELETE CASCADE)
Which means that I'm trying to create a UserAggregateId_FK
on ShoppingCart
even though the PK on UserAggregate
doesn't exist.
What can I do to use Unit of Work and ensure that the transaction will occur entirely?
I was trying to use 2 _context.SaveChangesAsync()
, one after each AddAsync
, but this is by no means a Unit of Work implementation and could leave users without ShoppingCarts
in the database, so I decided to use UoW.
EDIT:
Solved. As pointed by @Svyatoslav Danyliv and @heringer, I was passing UserAggregateId to ShoppingCart instead of UserAggregate. Efcore couldnt use the Id because the user entity was not created yet. Also, Unit of Work is not needed in this case, I just need to call one _context.SaveChangesAsync() now that the code is fixed.
Upvotes: 1
Views: 223
Reputation: 11
You should have properties of type your repositories in the unit of work class. Only through unit of work you can access your repositories.
public class UnitOfWork
{
private readonly yourContext _context;
public UnitOfWork(yourContext context, IUserRepository user)
{
_context = context;
_User = user;
}
public IUserRepository _User { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context. Dispose();
}
}
Upvotes: 1