Search code examples
c#entity-framework-corerepositoryasp.net-core-webapiunit-of-work

Asp.Net core Repository and Unit Of Work Pattern for Posting an entity


Trying to use an async method as I used to do with Repository Pattern to post an entity, but this time I wanted to integrate the Unit Of Work pattern, here is my interface:

public interface IUnitOfWork : IDisposable
{
    . . .
    void Save();
}

And its implementation:

public class UnitOfWork : IUnitOfWork
{
    private readonly DataContext _db;

    public UnitOfWork(DataContext db)
    {
        _db = db;
        . . .
    }
    . . .
    public void Dispose()
    {
        _db.Dispose();
    }

    public void Save()
    {
        _db.SaveChanges();
    }
}

And here is my method:

    [HttpPost]
    public async Task<IActionResult> CreateItem(string userId, ItemForCreationDto itemForCreationDto)
    {
        if (userId != User.FindFirst(ClaimTypes.NameIdentifier).Value)
            return Unauthorized();

        itemForCreationDto.UserId = userId;
        var item = _mapper.Map<Item>(itemForCreationDto);

        if (item == null)
            return BadRequest("Could not find item");

        _uow.Item.Add(item);

        if (await _uow.Save())                                       <--- Error here
        {
            var itemToReturn = _mapper.Map<ItemToReturnDto>(item);
            return CreatedAtRoute("GetItem",
                new { userId, id = item.Id }, itemToReturn);
        }

        throw new Exception("Creating the item failed on save");
    }

But I got the following erors:

Can't wait for 'void'

That's because I am trying to call a Save() method which is void from an async HttpPost method, I know that makes no sens, but till now I could not find how to implement that for this special case. When I tried removing the await I got the following error:

Unable to implicitly convert type 'void' to 'bool'

Any suggestion on how to implement that ?


Solution

  • Either refactor the interface to be async or add an additional member

    public interface IUnitOfWork : IDisposable {
    
        //. . .
    
        Task<bool> SaveAsync();
    }
    

    that can probably wraps the context's asynchronous API in the implementation if one exists

    public async Task<bool> SaveAsync() {
        int count = await _db.SaveChangesAsync();
        return count > 0;
    }
    

    allowing for the desired functionality

    //...
    
    if (await _uow.SaveAsync()){
        var itemToReturn = _mapper.Map<ItemToReturnDto>(item);
        return CreatedAtRoute("GetItem", new { userId, id = item.Id }, itemToReturn);
    }
    
    //...