将存储库接口作为参数传递给域类上的方法被认为是不好的设计吗?

dan*_*wig 2 domain-driven-design dependency-injection repository entity-framework-4.1

我们的域名模型现在非常贫乏.我们的实体大多是空壳,几乎完全是为了保存值和导航到集合而设计的.

我们使用EF 4.1代码优先ORM,到目前为止的设计是为了保护我们的新手开发人员免受可怕的"LINQ to Entities无法将blablabla转换为商店表达式"异常在早期迭代期间查询上下文时的异常.

我们在EF上有各种聚合根存储库接口.然而,impls中的一些代码块似乎应该是域的责任.只要在域中声明了存储库接口,并且impl在基础结构中(注入依赖关系),将存储库接口作为参数传递给实体(或其他域)类的方法是否被认为是错误的设计?

例如,这会不好?

public class EntityAbc {
    public void SaveTo(IEntityAbcRepository repos) {...}
    public void DeleteFrom(IEntityAbcRepository repos) {...}
}
Run Code Online (Sandbox Code Playgroud)

如果特定实体需要访问其他聚合根存储库,该怎么办?这样可以吗,为什么?

public void Save() {
    var abcRepos = DependencyInjector.Current.GetService<IEntityAbcRepository>();
    var xyzRepos = DependencyInjector.Current.GetService<IEntityXyzRepository>();
    // work with repositories
}
Run Code Online (Sandbox Code Playgroud)

更新1

我没有提到将代码移动到应用程序层,因为我考虑了一些使用IEntityAbcRepository来涉及业务规则实施的代码.存储库impl应尽可能为vanilla,对吧?它的主要职责应该是对ORM的简单抽象,允许您查找/添加/更新/删除实体.错误?

此外,此问题适用于其他非实体域类的方法 - 工厂,服务,任何模式可能是适当的.重点是,我问的是关于域类的任何方法的问题,而不仅仅是实体类.@Eranga,这是一个可以使用构造函数注入的地方,因为工厂和服务不是ORM的一部分.

然后,应用程序层可以通过将存储库impl注入其构造函数并将其作为参数传递给域服务或工厂来协调流.这是不好的做法吗?

更新2

在这里添加另一个澄清.如果域只需要访问IEntityAbcRepository以执行其Find()方法,该怎么办?在上面的示例中,SaveTo和DeleteFrom方法不会在存储库接口上调用任何添加/更新/删除方法.

到目前为止,为简单起见,我们在单个聚合根存储库接口上组合了fi​​nd/add/update/delete方法.但我想没有什么可以阻止我们将它们分成2个接口,如下所示:

  1. IEntityAbcReadRepository < - 定义所有查找方法签名
  2. IEntityAbcWriteRepository < - 定义所有添加/更新/删除方法sigs

在这种情况下,将IEntityAbcReadRepository作为参数传递给域方法是不好的做法?

Era*_*nga 5

与使用"服务定位器"模式的第二种方法相比,您的第一种方法更好.在第一种方法中,依赖性更明显.

以下是一些链接,解释了为什么"服务定位器"是一个糟糕的选择

这两种解决方案都源于EF不允许您使用构造函数注入的事实.但是,您可以使用属性注入,如本答案中所述.但这并不能保证存在强制依赖.

所以你的第一种方法是更好的解决方案.