我正在使用Unity作为依赖注入引擎。它包含“存储库”和“管理器”类的接口/类。这些存储库负责从/向DB中获取/保存/更新数据,以及管理者“了解”与其他组件/类的对象关系。
实现工厂以获取依赖容器的实例(每个请求1个实例)。当实例化任何存储库/管理器类时,它接收依赖性容器作为构造函数参数,并且可以在需要时创建所有其他管理器/存储库。
有两种方法可以创建业务实体:
因此,在这两种情况下,任何业务对象都有内部依赖容器,如果他需要获取任何数据,他可以获得适当管理器的实例并请求所需数据。
问题陈述:上周我读了一些关于SO的问题/答案,说明了这样的事情:
猜猜,同样适用于管理器/存储库类:我不应该将容器实例传递给它们的构造函数,而应该将接口放到其他必需的组件中。
对我而言似乎是合理的,但是:
我需要任何对象提供他需要的所有接口(通常,每个经理/存储库/实体需要3-5个);
很多情况下只需要1-2个接口(所以我不想创建很多其他接口);
问题1 :“隐藏”容器是否真的很好?为什么? (实际上,我觉得我知道为什么,但如果你有好的答案,请告知)。
问题2 :解决此类问题的良好做法是什么?
问题3 :在我的特定实现中,当我的对象从DB中提取时(我使用Linq2Sql,并考虑切换到EF)我无法通过DependencyContainer创建对象,我应该自己做(因为对象是使用在SQL站点上执行的表达式创建的,所以将调用无参数构造函数,并将以下数据分配给公共属性;并且SQL端不提供依赖性容器)。有没有解决办法?
我的实施技术细节:
Manager基类构造函数的示例:
public abstract class ManagerBase : IManager
{
protected ManagerBase(IUnityContainer container)
{
DependancyContainer = container;
}
protected readonly IUnityContainer DependancyContainer;
...
}
存储库基类示例:
public abstract class RepositoryBase<T, TDb> : IRepository<T>
where T : IEntity
where TDb : class, IDbEntity, new()
{
protected abstract ITable<TDb> GetTable();
public IQueryable<T> GetAll()
{
return GetTable().Select(GetConverter());
}
如何从DB中提取数据的示例:repository创建对象的实例并使用适当的DB数据初始化它们,其中“Container”字段已初始化:
public class CountryRepository
: RepositoryBase<ICountry, DbData.Country>, ICountryRepository
{
protected override Expression<Func<DbData.Country, ICountry>> GetConverter()
{
return dbEntity => new Country
{
DependancyContainer = DependancyContainer,
Code = dbEntity.CountryCode,
Name = dbEntity.CountryName,
};
}
当需要从DB获取数据时调用以下:
public class CountryManager : ManagerBase
{
ICountry GetCountryById(int countryId)
{
ICountryRepository repository = DependancyContainer.Resolve<ICountryRepository>();
return repository.GetAll()
.Where(country=>country.Id==countryId)
.SingleOrDefault()
;
}
}
答案 0 :(得分:2)
Q1:其他人可能不同意,但通常您不应将DI容器提供给您的域模型/实体类。我发现有两个主要原因:
Q2 :有人会说好的做法(在DDD下,存储库模式/强域模型模式来自)首先不会将您的实体类暴露给接口。相反,它们应该包含可以在不依赖于其他接口的情况下实现的任何业务逻辑,而更复杂的逻辑应该在Service类中(用DDD的说法)。
Q3 :您没有说明您正在使用哪种对象关系映射工具,但是可以通过某种拦截器/方面对实体对象实例化过程进行一些控制 - 面向编程模式。然后,这会使你的代码库更接近依赖于这个特定的O / R映射器及其功能(但是更难以在轨道上改变它,尽管我通常倾向于避免在做出架构选择时担心这一点。)
有关您的示例代码的更多观察结果可能会或可能不会指示您的代码库的其余部分:
CountryRepository.GetConverter()
类中执行的手动映射的更好替代方法。DbData
命名空间中的每个类构建并行实体类,可能是因为您无法将所需的服务插入DbData
命名空间类。也许我对 Q2 的回答会引导您走向更好的方向(如果可能的话,依靠服务并扩展DbData
类。)Manager
正在扮演什么角色......理想情况下,所有查询方法都应该在存储库中,这样他们才能真正对数据库执行SELECT ... FROM Country where Id = ?
查询而不是返回整个表并通过LINQ在内存中进行查询,毕竟这就是数据库所擅长的! (尽管对应用程序的性能特征进行了有意的缓存优化)。我相信GetCountryById
方法本身应该在CountryRepository
上。希望有所帮助!