如何在服务层中对业务实体完全收费

时间:2014-06-18 14:01:20

标签: asp.net-mvc domain-driven-design repository-pattern n-tier-architecture ddd-repositories

我无法为这个问题找到满意的解决方案。我有一个n层应用程序:

  1. UI
  2. 演示文稿(用作DTO的域模型,然后显示ViewModel)
  3. 业务层(域模型)
  4. 存储库和DAL(数据模型)
  5. 我的问题是我需要在业务层中使用完整对象。但是,我无法弄清楚加载它们的最佳方法是什么。这个问题可能看起来很愚蠢 - 也许是 - 但我对此感到非常困惑。我有以下课程(仅用于说明):

    public class Library
    {
        int ID {get;set;}
        string Name {get;set;}
        Book[] Novels {get;set;}
        Book[] TextBooks {get;set;}
    }
    
    public class Book
    {
        int ID {get;set;}
        Library[] SalePoints {get;set;}
        string Name {get;set;}
        string Type {get;set;}
    }
    

    我有两个服务方法LoadLibrary和LoadBook,其目的是填充这些相应的模型。我的问题是看起来我会陷入无限循环。我现在就解释自己。

    我预先加载了来自存储库的域模型(存储库使用valueinjecter(unflatenning)将数据模型转换为域模型,因此基本上简单的字段(int,string等等)填充在结果中域模型,但IEnumerable属性不是。这就是为什么我要在服务层加载它们的原因。(还有两个原因我无法在我的存储库中完全加载它们:1 /我使用通用存储库和2 /业务规则上的加载逻辑中继)

    让我们说我做了以下事情:

    public class LibrairiesProcessor
    {
        public Library LoadLibrairyObject(int ID)
        {
            Library l = UnitOfWork.LibraryRepo.GetByID(ID); // Only retrieve "simple" properties, here it will get the Name and the ID properties;
    
            l.Novels = UnitOfWork.BookRepo.Get(b=>b.LibrairyID==l.ID && b.Type="Novel");
            l.TextBooks= UnitOfWork.BookRepo.Get(b=>b.LibrairyID==l.ID && b.Type="TextBook");
    
    
            for(int i=0;i<l.Novels.Count();i++)
            {
                l.Novels[i] = BooksProcessor.LoadBookObject(l.Novels[i].ID);
            }
        }
    }
    

    public class BooksProcessor
    {
        public Book LoadBookObject(int ID)
        {
            Book b = UnitOfWork.LibraryRepo.GetByID(ID); // Only retrieve "simple" properties, here it will get the Name and the ID properties;
    
    
            b.SalesPoint = // Get From repo using the Unit of work
    
            for(int i=0;i<b.SalesPoint.Count();i++)
            {
                b.SalesPoint[i] = LibrairyProcessor.LoadLibraryObject(b.SalesPoint[i].ID);
            }
    
        }
    }
    

    难道没有无限循环吗? LoadLibraryObject()调用LoadBookObject(),反之亦然...尤其是当你来到SalePoint是触发LoadBookObject()的图书馆的书时......最多同样的工作做了两次,但我真的怀疑它会永远不会结束。

    所以我想知道我是否做得对。我的目标是拥有完全加载的对象,以避免在使用之前想知道对象是否足够,但我不确定我提出的解决方案。你通常如何实现这一目标?

    这看起来像一个微不足道的问题,但严重的是我无法弄清楚如何加载我的东西。我觉得自己陷入两难境地:

    1 /手动使用UnitOfWork.Repository填充所有属性和子属性,但是我会有很多代码和大量冗余代码。

    2 /与部分加载的域模型一起使用,其中一些属性设置为null,但我真的不想这样做。由于我的域模型很复杂,因此我没有直接使用EF对象,所以我无法使用他们的延迟加载。

    3 /从一个LoadObjectMethod调用Service LoadObject方法到另一个,以避免代码冗余,但看起来我引入了很多递归。

    我应该如何处理?

    谢谢!

1 个答案:

答案 0 :(得分:2)

这可能最适合CodeReview,但这里有一些想法可以为您省去一些麻烦:

  • 拥有一个完整的单独DAL对象模型可能有点矫枉过正。大多数现代ORM将为您处理域对象/数据库映射,而不会使用持久性内容污染您的域模型。请参阅Should I create in BLL project class the same like poco class in DAL project and return it to UI project if I want to display data from database?

  • 拥有通用存储库似乎是一个不能加载子实体列表的糟糕借口。至于&#34;加载逻辑依赖于业务规则&#34;,如果你指的是小说/文本书的区别,那么就有other, less class-intensive ways这样做。

  • &#34;由于我的域名模型很复杂,因此我没有直接使用EF对象,因此我无法使用他们的延迟加载内容#34; :你的模型到底有多复杂?从技术上讲,为什么你不能使用延迟加载?

  • 作为一种好的做法,聚合体不应该使用可导航的属性来引用彼此,而是使用(列表)ID。从存储库获取聚合根的对象如果要加载关联的聚合根,则会调用另一个存储库。

  • UnitOfWork.LibraryRepo看起来很尴尬。应该在方法中注入或直接实例化UoW,而不是以单例形式提供。存储库也是如此。如果您将ILibraryRepo传递给方法,那么事情会更加可测试且松散耦合。工作单元和存储库是两个独立的概念,它们以某种方式汇集在实体框架中,但是从外部来看,它们看起来并不像那样紧密相连。