Arthur Amorim
Arthur Amorim

Reputation: 11

How can I use Unit of Work to save two entities that are related 1:1 using Entity Framework Core and .NET? - SOLVED

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, CONSTRAINT FK_ShoppingCarts_Use rAggregates_UserAggregateId FOREIGN KEY (UserAggregateId) REFERENCES useraggregates (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

Answers (1)

Rebin
Rebin

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

Related Questions