Extending the data access layer

In order to extend our APIs with the related entities, we should start from the bottom of our stack. First of all, let's spread the capabilities of the data access layer by adding the following interfaces in the Repositories folder of the Catalog.Domain project:

// Repositories/IArtistsRepository.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Catalog.Domain.Entities;

namespace Catalog.Domain.Repositories
{
public interface IArtistRepository : IRepository
{
Task<IEnumerable<Artist>> GetAsync();
Task<Artist> GetAsync(Guid id);
Artist Add(Artist item);
}
}

// Repositories/IGenreRepository.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Catalog.Domain.Entities;

namespace Catalog.Domain.Infrastructure.Repositories
{
public interface IGenreRepository : IRepository
{
Task<IEnumerable<Genre>> GetAsync();
Task<Genre> GetAsync(Guid id);
Genre Add(Genre item);
}
}

Both the IArtistRepository and IGenreRepository interfaces reflect the routes initially defined in this section: the GetAsync method returns the list of the secondary entities, the GetAsync(Guid id) returns the single object, and the Add method allows us to create a new entity. We can now define the actual implementations of the specified interfaces. Likewise, the ItemRepository class implementations will be stored in the Catalog.Infrastructure project: 

//Repositories/ArtistRepository.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Catalog.Domain.Entities;
using Catalog.Domain.Repositories;

namespace Catalog.Infrastructure.Repositories
{
public class ArtistRepository : IArtistRepository
{
private readonly CatalogContext _catalogContext;
public IUnitOfWork UnitOfWork => _catalogContext;

public ArtistRepository(CatalogContext catalogContext)
{
_catalogContext = catalogContext;
}

public async Task<IEnumerable<Artist>> GetAsync()
{
return await _catalogContext.Artist
.AsNoTracking()
.ToListAsync();
}

public async Task<Artist> GetAsync(Guid id)
{
var artist = await _catalogContext.Artist
.FindAsync(id);

if (artist == null) return null;

_catalogContext.Entry(artist).State = EntityState.Detached;
return artist;
}

public Artist Add(Artist artist)
{
return _catalogContext.Artist.Add(artist).Entity;
}
}
}

The preceding code defines the ArtistRepository type and provides the implementation for the IArtistRepository interface. The class uses CatalogContext as a communication hub between our application and the SQL database. The GetAsync and GetAsync(Guid id) methods use the same pattern already implemented in the ItemRepository class to retrieve the information related to the required entities. Furthermore, the Add method refers to the Artists field exposed by CatalogContext to add a new artist. It is important to note that, in this case, the Add operation doesn't update the data source directly. 

Let's proceed by defining the GenreRepository class:

//Repositories/GenreRepository.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Catalog.Domain.Entities;
using Catalog.Domain.Repositories;

namespace Catalog.Infrastructure.Repositories
{
public class GenreRepository : IGenreRepository
{
private readonly CatalogContext _catalogContext;
public IUnitOfWork UnitOfWork => _catalogContext;


public GenreRepository(CatalogContext catalogContext)
{
_catalogContext = catalogContext;
}

public async Task<IEnumerable<Genre>> GetAsync()
{
return await _catalogContext.Genre
.AsNoTracking()
.ToListAsync();
}

public async Task<Genre> GetAsync(Guid id)
{
var item = await _catalogContext.Genre
.FindAsync(id);

if (item == null) return null;

_catalogContext.Entry(item).State = EntityState.Detached;
return item;
}

public Genre Add(Genre item)
{
return _catalogContext.Genre.Add(item).Entity;
}
}
}

In the same way as ArtistRepository, we are implementing the operations for querying and manipulating the Genre entities. Although the names of the methods and the implementations are quite similar, I have chosen to keep the repository interfaces separated and redefine each implementation separately. A quicker approach would be to create a generic class that represents the typical behavior of ItemRepository, ArtistRepository, and GenreRepository, but the generic repositories are not always the right choice. In addition to this, building the wrong abstraction is a lot more expensive than duplicating code, and building a unique generic repository for everything means tight coupling the entities.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.31.240