Implementing a Repository<T> that returns a domain model mapped from an EF Entity

元气小坏坏 提交于 2019-12-06 09:52:42
jgauffin

The repository pattern is used to provide an abstraction to the data layer? Right?

With that in mind, let's think about LINQ to SQL (no matter if it's through EF, nhibernate or anything else). There is no LINQ to SQL provider which is 100% fully compatible with LINQ. There are always cases which cannot be used. Hence LINQ to SQL is a leaky abstraction.

That means that if you use a repository interface which exposes IQueryable<TDomainModel> or Expression<Func<TDb, bool>> where you have to be aware of those limitations. It's therefore not a complete abstraction.

Instead I recommend that you just provide a basic generic repository like this:

interface IRepository<TEntity, TKey>
{
    TEntity Get(TKey key);
    void Save(TEntity entity);
    void Delete(TEntity entity);
}

And then create root aggregate specific interfaces:

interface IUserRepository : IRepository<User, int>
{
    User GetByUserName(string userName);
    IEnumerable FindByLastName(string lastName);
}

which means that the implementation would look like:

public class UserRepository : EfRepository<User>, IUserRepository
{
    //implement the interfaces declared in IUserRepository here
}

It's now a 100% working abstraction where it's much easier to tell what functions the repository provides. You have to write a little bit more code now, but you don't have to struggle with a leaky abstraction later on.

You could also switch to queries like I demonstrate here: http://blog.gauffin.org/2012/10/griffin-decoupled-the-queries/

take a look at AutoMapper. This may help with the generic mapping.

You are going in a right way, but I will suggest to add additional abstractions into your solution:

public abstract class RepositoryBase<T, TDb> : where T : new() where TDb : class, new()
{
    protected IQueryable<T> GetBy(Expression<Func<TDb, bool>> where = null,
                                  PagingSortOptions? pagingSortOptions = null)
    {
        //GetDbSet basic method to get DbSet in generic way 
        IQueryable<TDb> query = GetDbSet();

        if (where != null)
        {
            query = query.Where(where);
        }

        if (pagingSortOptions != null)
        {
            query = query.InjectPagingSortQueryable(pagingSortOptions);
        }

        return query.Select(GetConverter());
    }

    protected virtual Expression<Func<TDb, T>> GetConverter()
    {
        return dbEntity => Mapper.Map<TDb, T>(dbEntity);
    }
}

public class CountryRepository : RepositoryBase<CountryDomainModel, CountryDb>, ICountryRepository
{
    public Country GetByName(string countryName)
    {
        return GetBy(_ => _.Name == countryName).First();
    }
}

public interface ICountryRepository : IRepository<CountryDomainModel>
{
    Country GetByName(string countryName);
}

public interface IRepository<TDomainModel>
{
    //some basic metods like GetById
}

than outside database layer you will use ICountryRepository.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!