기본 사항부터 살펴 보겠습니다.
마찬가지로 이름이 지정된 바인딩은 [Named("foo")]
속성과 같은 코드에서 비롯된 상수 값으로 만 작동하거나 IResolutionRoot.Get<T>(string name)
과 같은 "서비스 위치"를 사용하여 작동합니다. 시나리오 중 하나가 작동하지 않으므로 명명 된 바인딩이 문제가되지 않습니다. 그러면 조건부 바인딩이 생깁니다 (.When(...)
메쏘드).
각각 n 개의 엔티티가있는 2 개의 데이터베이스가 있습니다. 2 데이터베이스는 두 개의 구성이 두 개의 다른 의미 인 IUnitOfWork
구성을 의미합니다. 그러나 "사용자"는 특정 데이터베이스가 아니라 특정 엔터티를 요청하고 있습니다. 따라서지도 entity-->database
(사전)이 필요합니다. 나는 그걸 해결할 방법이 없다고 생각하지만, 컨벤션을 통해 구현하는 일종의 컨벤션을 고안 할 수도 있습니다. 그래서 많은 코드를 타이핑하고 유지할 필요가 없습니다.
해결 방법 1 : 상자 Ninject에 기능을 밖으로 .WhenInjectedInto<>
, 그리고 육체 노동을 많이 :
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseA>()
.WhenInjectedInto<IRepository<SomeEntityOfDatabaseA>>();
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseA>()
.WhenInjectedInto<IRepository<SomeOtherEntityOfDatabaseA>>();
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseB>()
.WhenInjectedInto<IRepository<SomeEntityOfDatabaseB>>();
당신이 바로 .. 드리프트를 얻을?
솔루션 2.1 : 사용자 정의 When(..)
구현
더 이상 육체 노동 및 유지 보수 순전히 없음. 내가 당신에 코드를 덤프하자, 아래 참조 :
공용 인터페이스 IRepository { IUnitOfWork의 UnitOfWork {얻을; } }
public class Repository<TEntity> : IRepository<TEntity>
{
public IUnitOfWork UnitOfWork { get; set; }
public Repository(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
}
public interface IUnitOfWork { }
class UnitOfWorkA : IUnitOfWork { }
class UnitOfWorkB : IUnitOfWork { }
public class Test
{
[Fact]
public void asdf()
{
var kernel = new StandardKernel();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>));
kernel.Bind<IUnitOfWork>().To<UnitOfWorkA>()
.When(request => IsRepositoryFor(request, new[] { typeof(string), typeof(bool) })); // these are strange entity types, i know ;-)
kernel.Bind<IUnitOfWork>().To<UnitOfWorkB>()
.When(request => IsRepositoryFor(request, new[] { typeof(int), typeof(double) }));
// assert
kernel.Get<IRepository<string>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkA>();
kernel.Get<IRepository<double>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkB>();
}
private bool IsRepositoryFor(IRequest request, IEnumerable<Type> entities)
{
if (request.ParentRequest != null)
{
Type injectInto = request.ParentRequest.Service;
if (injectInto.IsGenericType && injectInto.GetGenericTypeDefinition() == typeof (IRepository<>))
{
Type entityType = injectInto.GetGenericArguments().Single();
return entities.Contains(entityType);
}
}
return false;
}
}
솔루션 2.2 사용자 정의 규칙
When(...)
이의 작은 규칙을 소개하겠습니다 기반. TRZIC 데이터베이스의 엔터티 이름은 TRZIC
으로 시작합니다 (예 : TRZIC_Foo
). 데이터베이스 INIC의 엔터티 이름은 과 같이 INIC
으로 시작됩니다. 우리가 명시 적으로 매핑 (EntityA, EntityB, EntityC) => DatabaseA
, (EntityD, EntityE, EntityF) => DatabaseB)
필요하지 않습니다
public class Test
{
[Fact]
public void asdf()
{
var kernel = new StandardKernel();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>));
kernel.Bind<IUnitOfWork>().To<UnitOfWorkA>()
.When(request => IsRepositoryFor(request, "TRZIC")); // these are strange entity types, i know ;-)
kernel.Bind<IUnitOfWork>().To<UnitOfWorkB>()
.When(request => IsRepositoryFor(request, "INIC"));
// assert
kernel.Get<IRepository<TRZIC_Foo>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkA>();
kernel.Get<IRepository<INIC_Bar>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkB>();
}
private bool IsRepositoryFor(IRequest request, string entityNameStartsWith)
{
if (request.ParentRequest != null)
{
Type injectInto = request.ParentRequest.Service;
if (injectInto.IsGenericType && injectInto.GetGenericTypeDefinition() == typeof (IRepository<>))
{
Type entityType = injectInto.GetGenericArguments().Single();
return entityType.Name.StartsWith(entityNameStartsWith, StringComparison.OrdinalIgnoreCase);
}
}
return false;
}
}
이 방법 : 우리는 지금 이전 솔루션을 적용 할 수 있습니다.
이전 질문에서 제안한 인터페이스를 사용해보십시오. –
@Alex 두 데이터베이스 모두에 동일한 'IGenericRepository'를 사용하고 있기 때문에 여기서 인터페이스를 사용할 수 없습니다. 여기서, IUnitOfWork 구현은 TEntity에 의존합니다. – VansFannel