Контейнер Unity RegisterTypeвопросы - PullRequest
3 голосов
/ 08 июня 2011

Я пытаюсь сделать автоматическую регистрацию репозиториев:

Это работает, но мне это не нравится, потому что в классах слоя Service вместо этого мне придется поставлять конкретный EntityRepository<T> конструкторам.поставки интерфейса IRepository<T>

public static IContainer RegisterRepositories(
    this IContainer container, params Assembly[] assemblies)
{
    var repositories = (
        from assembly in assemblies
        from type in assembly.GetTypes()
        where typeof(ObjectContext).IsAssignableFrom(type)
        from property in type.GetProperties()
        let propertyType = property.PropertyType
        where propertyType.IsGenericType 
        where propertyType
            .GetGenericTypeDefinition() == typeof(ObjectSet<>)
        select new 
        {
            ObjectContextType = type, 
            DomainType = propertyType.GetGenericArguments()[0] 
        })
        .ToList();

    foreach (var repository in repositories)    
    {
        container.RegisterType(typeof(BaseObjectContext), 
            new PerExecutionContextLifetimeManager());

        var serviceType = typeof(IRepository<>)
            .MakeGenericType(repository.DomainType);

        var implementationType = typeof(EntityRepository<>)
            .MakeGenericType(repository.ObjectContextType);

        container.RegisterType(serviceType, implementationType, 
            new TransientLifetimeManager());
    };

    return container;
}

Я хочу автоматически зарегистрировать свои репозитории, используя container.RegisterType<TFrom, TTo>(new TransientLifetimeManager()); Я знаю, в чем проблема, потому что этот способ регистрации требует, чтобы вы указали реальное имя интерфейса икласс, такой как IRepository<Customer> и EntityRepository<Customer>.Я могу сделать это, но мне придется перечислять репозитории один за другим, и я не думаю, что это осуществимо, если вы имеете дело с проектом из 100 объектов Domain.Я хочу сделать их автоматически, например, так, чтобы я мог вставить IRepository<T> в классы слоя Service.

// Configure root container.Register types and life time 
// managers for unity builder process
public static IContainer RegisterRepositories(
    this IContainer container, params Assembly[] assemblies)
{
    var repositories = (
        from assembly in assemblies
        from type in assembly.GetTypes() 
        where typeof(ObjectContext).IsAssignableFrom(type)
        from property in type.GetProperties()
        let propertyType = property.PropertyType
        where propertyType.IsGenericType 
        where propertyType
            .GetGenericTypeDefinition() == typeof(ObjectSet<>)
        select new 
        {
            ObjectContextType = type, 
            DomainType = propertyType.GetGenericArguments()[0] 
        })
        .ToList()

    foreach (var repository in repositories)
    {
        container.RegisterType<BaseObjectContext>(
            new PerExecutionContextLifetimeManager(), 
            new InjectionConstructor());

        container.RegisterType<IRepository<repository.DomainType>,
             EntityRepository<repository.ObjectContextType>>(
            new TransientLifetimeManager());
    };

    return container;
}

1 Ответ

1 голос
/ 09 июня 2011

Я не совсем уверен, в чем проблема, которую вы пытаетесь решить, но я не думаю, что ваш дизайн будет работать в долгосрочной перспективе. Однако для меня ясно, что у вас большой домен, и вы хотите иметь возможность внедрять IRepository<T> экземпляры в классы обслуживания, но хотите воспользоваться преимуществами регистрации пакетов и генератора кода Entity Framework, чтобы вы не могли необходимость поддерживать много кода, что является замечательной целью.

Однако вы пытаетесь внедрить IRepository<T> экземпляров в службы. Хотя репозиторий является распространенным шаблоном проектирования, внедрение репозиториев непосредственно в сервисы никогда не работало для меня и кажется странным в контексте Entity Framework, который использует шаблон единицы работы (ObjectContext) для централизации операций между приложением и базой данных. Внедрение репозиториев означает, что под каждым репозиторием должно быть указано ObjectContext, и вы, вероятно, хотите иметь одинаковые ObjectContext во всех экземплярах репозитория, которые вы внедряете в одной службе, потому что ваши операции, вероятно, должны быть атомарными.

IMO, было бы лучше не внедрять IRepository<T> экземпляров в ваши сервисы, а внедрять UnitOfWork или даже лучше: IUnitOfWorkFactory. IUnitOfWorkFactory может затем создать новый экземпляр UnitOfWork (который служба должна утилизировать после завершения), а UnitOfWork будет содержать список IRepository<T> экземпляров и содержать метод SubmitChanges.

Внедрив метод IRepository<T> GetRepository<T>() в UnitOfWork, вы можете эффективно получить конкретный репозиторий без необходимости какой-либо регистрации пакета, как обычно, чтобы подключить ваши 100 репозиториев. Это можно сделать внутри реализации IUnitOfWork.

С точки зрения приложения было бы еще лучше, если бы UnitOfWork содержал свойства для конкретных реализаций IRepository<T>, таких как public IRepository<Customer> Customers { get; set; }, но это означает, что вам нужно будет добавлять новые свойства, когда новые сущности добавляются в система, которая, вероятно, не то, что вам нравится. Однако, по моему опыту, это не сильно влияет на удобство сопровождения, хотя значительно улучшает читабельность вашего кода.

Этот дизайн может показаться вам немного надуманным, но на самом деле у меня есть аналогичный дизайн, работающий уже более полугода, и он отлично работает. Я писал об этом в блоге (см. Подделка вашего поставщика LINQ ), и другие успешно применили этот подход в своих приложениях. Кажется, это работает и для других. Возможно, вам это интересно, или, по крайней мере, он может дать вам некоторые идеи, как эффективно это сделать. Я использую внедрение зависимостей, и с учетом данного дизайна мне просто нужно настроить несколько типов, чтобы запустить его.

Надеюсь, это поможет.

...