存储库和服务设计问题

时间:2010-02-22 18:31:12

标签: c# domain-driven-design service repository-pattern

我们正在尝试找出使用DDD时的最佳做法,我们正在就最有意义或“正确的方式”进行讨论。

注意:所有代码都是伪代码。

以下是:

public interface IDomainEntityAService
{
    void CreateMyObject(DomainEntityA myobject);
    DomainEntityA RetrieveDomainEntityA(long someId);
    //Other operations that handle the business logic dealing with MyObject
}

我们还有另一项服务,它使用部分IDomainEntityAService来满足特殊需求。

public interface IDomainEntityBService
{
    DomainEntityB GetDomainEntityB();
}

其中OtherInformation包含以下内容:

public class DomainEntityB
{
    public string Name { get; set; }
    public IList<DomainEntityA> DomainEntityAList { get; set; }
}

现在问我们了。我们正在考虑使用存储库来持久保存OtherInformation,如下所示:

public interface IDomainEntityBRepository
{
    void Add(DomainEntityB information);
    DomainEntityB Get(long someId);
}

由于我们希望尽可能保持DRY,我们理想地希望重用IDomainEntityAService的逻辑来检索DomainEntityB的DomainEntityAList列表。哪一个最有意义?

A)在IDomainEntityBRepository中引用IDomainEntityAService e.g。

public class SqlDomainEntityBRepository : IDomainEntityBRepository
{

    public SqlDomainEntityBRepository(IDomainEntityAService domainEntityAService, Database database)
    {

    }

    public void Add(DomainEntityB information)
    {
        //save DomainEntityB to SQL
    }
    public DomainEntityB Get(long someId)
    {
        //Get OtherInformation.Name from SQL
        //use domainEntityAService.Get() to populate the list of DomainEntityAList
        //return DomainEntityB
    }
}

B)IDomainEntityBRepository只处理SQL内容,我们使用IHaveOtherInformation的服务层来填充MyObjects列表

public class DomainEntityBService : IDomainEntityBService
{
    public DomainEntityBService(IDomainEntityAService domainEntityAService, IDomainEntityBRepository repo)
    {
    }
    public DomainEntityB GetDomainEntityB()
    {
        var domainEntityB = _repo.Get(someId);
        domainEntityB.DomainEntityAList = _domainEntityAService.GetAll(someId);
        return domainEntityB;
    }
}

C)我们为OtherInformation创建一个特定的DAL对象,我们使用服务层来组成OtherInformation的一个实例

public class DomainEntityBDAL
{
    public string Name { get; set; }
    public IList<int> DomainEntityAListIds { get; set; }
}

然后我们将有一个存储库来检索OtherInformationDAL,然后代码如下所示:

public class DomainEntityBService : IDomainEntityBService
{

    public DomainEntityBService(IDomainEntityAService domainEntityAService, IDomainEntityBRepository repo)
    {
    }
    public DomainEntityB GetDomainEntityB()
    {

        var domainEntityBDAL = _repo.Get(someId);
        DomainEntityB result = new DomainEntityB() { Name = domainEntityBDAL.Name };
        foreach (var id in domainEntityBDAL.DomainEntityAListIds)
        {
            result.DomainEntityAList.Add(_domainEntityAService.Get(id));
        }
        return result;
    }
}

D)哇,我们完全偏离基地这样做!!!

我希望这是有道理的,谢谢你的帮助。

编辑便笺:

也许英文描述可以帮助更好地描述我的问题。我们有DomainEntityA,它是一个聚合根。有一个相应的服务来处理处理DomainEntityA的所有逻辑。

现在我们还有DomainEntityB,它是一个聚合根。但是DomainEntityB有一个DomainEntityAs列表。 DomainEntityAs可以独立生存,但DomainEntityB不能没有DomainEntityAs列表

我们如何加载DomainEntityB中的DomainEntityA项列表并维护DomainEntityA的所有逻辑。

在DomainEntityBService中重用DomainEntityAService?
在DomainEntityBService中创建一个单独的DomainEntityARepository?

我们目前使用的是EntLib,但是正在查看有关设计的信息,然后是DAL实现。

2 个答案:

答案 0 :(得分:0)

我在这里假设您将要存储到数据库中。

对此的答案很大程度上取决于您使用的持久性引擎。如果您手动滚动自己的持久性,则C不是一个选项,因为您将看到N + 1个查询。 B很可能是我的第一选择,因为它提供了最多的代码重用,希望是非常糟糕的性能。

说过如果你使用像NHibernate这样的东西,我建议你不要使用存储库模式而是

  • 将复杂查询封装为对象(然后可以进行单元测试)。
  • 直接使用会话

我希望这有帮助!

答案 1 :(得分:0)

您如何使用允许您插入类型的通用界面?像这样:

public interface IRepository<T>
{
    T Get(object id);
    void Save(T value);
    void Update(T value);
    void Delete(T value);
    IList<T> GetAll();
}

您使用的任何实现都应该能够读取类型并知道它如何适合数据库。简而言之,这就是存储库模式。如果您没有完全设置Entlib,请浏览NHibernate。我发现它很好地补充了存储库模式。我在我的博客上写了this topic的大量文章,所以如果你想了解更多,你可以去那里。