Question

I am trying to define the appropriate interfaces and classes to create a repository interface and a base repository class that does common things every repository will need. Then I also want to define a repository for a specific entity type which is also defined in an interface of it's own.

So far I've come up with the following:

// The repository interface:

/// <summary>
/// Defines the methods of the base repository
/// </summary>
/// <typeparam name="TEntity">An entity class</typeparam>
public interface IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// Retrieves all the entities
    /// </summary>
    /// <returns>A query able set of entities</returns>
    IQueryable<TEntity> Get();
}

// An abstract implementation of it, which all repositories will inherit from:

/// <summary>
/// Represents the base repository from which all database bound repositories inherit
/// </summary>
/// <typeparam name="TEntity">The entity type this repository handles</typeparam>
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// Retrieves all the entities
    /// </summary>
    /// <returns>A query able set of entities</returns>
    public virtual IQueryable<TEntity> Get()
    {
        return this.Context.Set<TEntity>();
    }
}

A specific interface for the user entity:

/// <summary>
/// Represents a user
/// </summary>
public class User
{
    public string Login { get; set; }
    public string Password { get; set; }
}

/// <summary>
/// Defines the interface for user repository implementations
/// </summary>
/// <typeparam name="TEntity">A user entity</typeparam>
public interface IUserRepository<TEntity> : IRepository<TEntity> where TEntity : User
{
    void Authenticate(TEntity user);
}

// and it's implementation:

/// <summary>
/// Represents a database bound repository that handles user entities
/// </summary>
/// <typeparam name="TEntity">A user entity</typeparam>
public class UserRepository<TEntity> : BaseRepository<TEntity>, IUserRepository<TEntity> where TEntity : User
{
    public void Authenticate(TEntity user)
    {
        // do some stuff here
    }
}

The above works fine but in order to instantiate a UserRepository I have to write var users = new UserRepository<User>()

It is obvious that the generic in UserRepository can only be of type User, so I would like to find a way not having to explicitly write this. I'd like to be able to write var users = new UserRepository() instead.

Also, while writing tests, I have to create mocks of the IUserRepository like this:

var usersMock = new Mock<IUserRepository<User>>();

Here I'd also like to be able to write something like this:

var usersMock = new Mock<IUserRepository>();

This may be a XY problem, so I am open to different overall implementation suggestions.

Was it helpful?

Solution

You could implement the specific interfaces:

public interface IUserRepository : IRepository<User>
{
    void Authenticate(Useruser);
}

// and it's implementation:

public class UserRepository : BaseRepository<User>, IUserRepository
{
    public void Authenticate(User user)
    {
        // do some stuff here
    }
}

Your interfaces can have generic type parameters, but when you implement an interface you can specify these arguments. Your implementation does not need to be generic as well

OTHER TIPS

If you are always using a specific class or interface for a certain class' inheritance/implementation, then you do not need to tack on generics to it.

Here's an example below and hopefully what you were asking for:

public interface IUserRepository : IRepository<IUser>
{
    void Authenticate(IUser user);
}

public class UserRepository : BaseRepository<User>, IUserRepository
{
    public void Authenticate(IUser user)
    {
        // do some stuff here
    }
}

You can now instantiate and mock without having to specify the generic that will probably always be the same.

var repository = new UserRepository();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top