views:

65

answers:

3
public interface IRepository<T> where T : Entity
{
    void Delete(T entity);
    T[] GetAll();
    T GetById(int id);
    void SaveOrUpdate(T enity);
    void Merge(T entity);
}

public interface ITeamEmployeeRepository : IRepository<TeamEmployee>
{
    PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize);
}


public class Repository<T> : IRepository<T> where T : Entity
{
    private readonly ISession _session;

    protected Repository()
    {
        _session = GetSession();
    }

    public virtual void Delete(T entity)
    {
        _session.Delete(entity);
    }

    public virtual T[] GetAll()
    {
        return _session.CreateCriteria<T>().List<T>().ToArray();
    }

    public virtual T GetById(int id)
    {
        return _session.Get<T>(id);
    }

    public virtual void SaveOrUpdate(T enity)
    {
        _session.SaveOrUpdate(enity);
    }

    public void Merge(T entity)
    {
        _session.Merge(entity);
    }

    protected ISession GetSession()
    {
        return new SessionBuilder().GetSession();
    }
}

public class TeamEmployeeRepository : Repository<TeamEmployee>, ITeamEmployeeRepository
{
    public PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize)
    {
        return GetSession().QueryOver<TeamEmployee>()
            .Fetch(x => x.Employee).Eager
            .Fetch(x => x.Team).Eager
            .ToPagedList(pageIndex, pageSize);
    }
}

For now I register the repository as follows:

For<ILoanedItemRepository>().Use<LoanedItemRepository>();
For<ITeamEmployeeRepository>().Use<TeamEmployeeRepository>();
For<IArticleRepository>().Use<ArticleRepository>();
For<ISalesmanRepository>().Use<SalesmanRepository>();
For<ISalesmanArticleRepository>().Use<SalesmanArticleRepository>();
For<IGoodsGroupRepository>().Use<GoodsGroupRepository>();
For<IEmployeeRepository>().Use<EmployeeRepository>();

This is really cumbersome, especially if there comes along new repositories.

An easier and better registration would be:

For(typeof(IRepository<>)).Use(typeof(Repository<>));

But this does not work. StructureMap is everytime saying me that no Default Instance defined for PluginFamily Core.Domain.Bases.Repositories.ITeamEmployeeRepository.

I searched on stackoverflow and found something new:

Scan(x =>
{
    x.AssemblyContainingType(typeof(TeamEmployeeRepository));
    x.AddAllTypesOf(typeof (IRepository<>));
    x.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});

But still the same error message.

How do I have to register my repositories with StructureMap 2.6.1.0?

A: 

I recently solved something similar by doing a small redesign, which made everything so much simpler. This might work for you as well. You might try removing the specific interfaces such as ITeamEmployeeRepository and ILoanedItemRepository from your design. The way I did this was by using extension methods. Here is an example:

public static class RepositoryExtensions
{
    public static TeamEmployee GetById(
        this IRepository<TeamEmployee> repository, int id)
    {
        return repository.Single(e => e.TeamEmployeeId == id);
    }

    public static IQueryable<Salesman> GetActiveSalesmen(
        this IRepository<ISalesmanRepository> repository)
    {
        return repository.Where(salesman => salesman.Active);
    }

    // etc
}

After that I created an IRepositoryFactory that allowed me to create repositories of a certain type:

public interface IRepositoryFactory
{
    IRepository<T> CreateNewRepository<T>();
}

When having this interface in place it is easy to create an implementation of this factory that asks the container to create a concrete Repository<T>. The RepositoryFactory could look like this:

public class RepositoryFactory : IRepositoryFactory
{
    public IRepository<T> CreateNewRepository<T>()
    {
        return ObjectFactory.GetInstance(typeof(Repository<T>));
    }
}

With this design you only have to register the concrete RepositoryFactory by its IRepositoryFactory interface and you are done. Instead of injecting IRepository<ITeamEmployeeRepository> in the old design, you now inject an IRepositoryFactory and let the client call the CreateNewRepository<T> method. Because of the use of extension methods you can call type specific methods on the repository.

Another advantage of this is that you don't need to re-implement the methods that you initially defined on ITeamEmployeeRepository on every implementation.

This design worked very well in my situation, especially because my IRepository<T> interfaces make use of expression trees. Of course it is not possible for me to see if such design works for you but I hope it will.

Good luck.

Steven
"Another advantage of this is that you don't need to re-implement the methods that you initially defined on ITeamEmployeeRepository on every implementation." This is not the case, because the Repository<T> is already implementing the standard CRUD stuff. The specific ITeamEmployeeRepository has only specific requirements.
Rookian
Perhaps I misunderstand, but I imagined that you would use the `ITeamEmployeeRepository` for team employee specific methods. These methods would have no meaning in the `Repository<T>` class. I suppose you have entity specific methods on that interface, because an interface without methods would not be very useful. Things like `GetByYear` or CRUD operations that have no meaning on Repository<T>. You would normally have at least two implementations of this `ITeamEmployeeRepository` interface...
Steven
One in your production environment and one for your unit testing environment. This means that in that situations, you would have to implement `GetByYear` in both your production `TeamEmployeeRepository` and the using test repository. With a extension method you not only save yourself from having to write it multiple times, but it allows you to cover that code. But again, perhaps I misunderstand your needs.
Steven
I have a specific interface for my specific repositories + a general generic repository. A specific empty interface is necessary, because I do not use Repository<AnyEntity> and I can't use it because it is not instanciatable.
Rookian
A: 

You will need to create your own ITypeScanner and register it in your Scan() call. Look at the source code of GenericConnectionScanner as a starting point. Instead of searching the types to see if they implement IRepository<T>, you will look to see if they implement any interface that implements IRepository<T>, and then register the type for that interface.

UPDATE: All the talk of IRepository<T> had me over-thinking this, when it's really an irrelevant details. Just use the DefaultConventions scanner as suggested by Rookian.

Joshua Flanagan