StructureMap - Как зарегистрировать и разрешить открытый универсальный тип - PullRequest
8 голосов
/ 31 октября 2010
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<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>();

Это действительно громоздко, особенно если появляются новые репозитории.

Проще и лучше зарегистрироваться:

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

Но это не работает.StructureMap всегда говорит мне, что для PluginFamily Core.Domain.Bases.Repositories.ITeamEmployeeRepository не определен экземпляр по умолчанию.

Я искал в stackoverflow и нашел что-то новое:

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

Но все равносообщение об ошибке.

Как мне зарегистрировать свои репозитории в StructureMap 2.6.1.0?

Ответы [ 4 ]

9 голосов
/ 01 ноября 2010

Я нашел решение.

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

WithDefaultConventions - важная часть показанного кода, потому что с этим параметром вы говорите StructureMap, чтобы использовать соглашение по отображению ITeamEmployeeRepository вTeamEmployeeRepository.Поэтому StructureMap исходит из предположения, что класс назван так же, как и имя интерфейса без префикса I .

3 голосов
/ 13 ноября 2013

Я нашел этот вопрос, прибегая к помощи "Structuremap Resolution generic".Существующие ответы хорошие, но сложные.Для тех, кто ищет простой ответ: для интерфейса ISome и реализации класса Some мы пишем

c.For<ISome>().Use<Some>()

, а для универсального ISome и реализации класса Some мы пишем

c.For(typeof(ISome<>)).Use(typeof(Some<>))

Иэто все

0 голосов
/ 31 октября 2010

Вам нужно будет создать свой собственный ITypeScanner и зарегистрировать его в своем вызове Scan(). Посмотрите на исходный код GenericConnectionScanner в качестве отправной точки. Вместо того, чтобы искать типы, чтобы увидеть, реализуют ли они IRepository<T>, вы посмотрите, реализуют ли они какой-либо интерфейс, который реализует IRepository<T>, а затем зарегистрируете тип для этого интерфейса.

ОБНОВЛЕНИЕ: все разговоры о IRepository<T> заставили меня задуматься над этим, когда это действительно не имеет значения детали. Просто используйте сканер DefaultConventions в соответствии с рекомендациями Rookian.

0 голосов
/ 31 октября 2010

Недавно я решил что-то подобное, выполнив небольшой редизайн, который сделал все намного проще.Это может сработать и для вас.Вы можете попробовать удалить определенные интерфейсы, такие как ITeamEmployeeRepository и ILoanedItemRepository из вашего дизайна.Я сделал это с помощью методов расширения.Вот пример:

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
}

После этого я создал IRepositoryFactory, который позволил мне создавать репозитории определенного типа:

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

Когда этот интерфейс установлен на месте, онЛегко создать реализацию этой фабрики, которая просит контейнер создать бетон Repository<T>.RepositoryFactory может выглядеть так:

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

При таком дизайне вам нужно зарегистрировать бетон RepositoryFactory только через интерфейс IRepositoryFactory, и все готово.Вместо внедрения IRepository<ITeamEmployeeRepository> в старом дизайне, вы теперь внедряете IRepositoryFactory и позволяете клиенту вызывать метод CreateNewRepository<T>.Из-за использования методов расширения вы можете вызывать специфичные для типа методы в репозитории.

Еще одно преимущество этого заключается в том, что вам не нужно повторно реализовывать методы, которые вы изначально определили в ITeamEmployeeRepository на каждомреализация.

Этот дизайн очень хорошо работал в моей ситуации, особенно потому, что мои IRepository<T> интерфейсы используют деревья выражений.Конечно, я не могу увидеть, работает ли такой дизайн для вас, но я надеюсь, что он будет.

Удачи.

...