具有干净持久层的域类/实体(DAO,工厂,......)

时间:2013-07-22 20:40:05

标签: orm associations entity dao abap

将域对象/实体与没有 ORM框架支持的持久层结合起来的简洁方法是什么?

我有域类/实体zcl_documentzcl_document_request(1:n)。我希望Domain Classes只包含核心域逻辑, no 基础架构,没有“帮助器”,没有持久性/加载机制。

在ABAP中,我为每个公开定义了“干净”structures zs_documentzs_docreq作为公共只读data属性(我们是毕竟在ABAP中)。这样我就不需要在实体上使用一堆getter,并最小化核心域逻辑的方法。

为了获得一个瘦的持久层,我已经定义了DAO - 每个数据库表readsavefind_by_x的接口(包括可选的文本表)和东西)。它们的返回类型始终是structure或结构表,不是实体对象本身。所以我有一个可测试/可替换的薄持久层。此持久性层现在也可用于执行大量数据处理的报表,因为我不会被迫创建对象实例或对象图,我可以求助于(希望是干净的)结构。

要实例化实体,通常每个实体都有一个公共静态create(工厂)方法,它采用“干净”结构,验证并生成其实例。与其他对象具有基本关联的实体更难以create,因为还必须创建依赖对象。这些成员得到他们自己的zcl_document_request_manager(承担命名)。经理知道如何create(工厂)和save实体,包括所有相关对象。因此,它也是friend个实体。

工厂是唯一知道DAO的地方,以保持实体本身免受基础设施/持久性的影响。加载是热切的,我不知道如何在实体中没有太多基础设施管理代码的情况下创建透明的延迟加载。

使用它将如下所示:

create object lo_docreq_mng exporting dao, dao, dao, dao,...

lt_docreq = docreq_dao->find_by_x( ... ) // table of structure

foreach lt_docreq as ls_docreq // structure
  lo_docreq = lo_docreq_mng=>create( ls_docreq ) // factory => instance

  lo_doc = lo_docreq->get_document( ) // was created with document-instance

  lo_docreq->do_something_mutating( ).      
  lo_docreq_mng->save( lo_docreq) // save including dependent objects

这可行还是有味道? 任何评论都赞赏。

2 个答案:

答案 0 :(得分:2)

我喜欢你的方法。我会改变一些事情:

1)为了保持域对象的用户清除构造代码,你可以提供一个docreq-class,它返回一个实体列表而不是结构:

lt_doc = doc_qry->find_by_x( ... ) // table of entities
foreach lt_doc as lo_doc 
  lo_doc->do_something_mutating( ).      
  lo_doc_mng->save( lo_doc ) // save including dependent objects

该用法不易出错,并澄清了代码中的业务逻辑。并且由于希望您的网站经常被使用,因此您可以简化其他开发人员的使用。

2)也许你也可以摆脱save-Method。为什么你必须明确地调用save?根据我的经验,保存或丢弃内容的决定被放置到正在运行的事务的控制器(顶级报告或运行UI)。但它不应该被置于某种业务或服务方法/功能中。

3)我不会选择静态方法。首先,它们很容易实现,但是对于以后的更改,它们可能会成为地狱

关于使用ORM的讨论:我不会混淆持久性和域逻辑,因为它会降低可测试性。 ABAP-ORM仅作为持久层使用没有太大的好处。为什么要将数据包装在一个类中并将其用作简单的abap-structure(在大多数情况下)?另一方面,它缺乏一个很好的DQL。

答案 1 :(得分:0)

我知道这是一个老问题,但在我最近的项目中,我一直试图为同样的问题找到一个很好的解决方案。

我通常同意你的方法并遵循一个非常类似于你的方法,除非我没有定义任何DAO类型的对象。大多数情况下,我不只是定义一个管理器类,而是两个单独的类:一个用于管理数据库检索/保存的存储库和一个用于创建新的有效实例的工厂。这只是为了不违反SRP(我也倾向于将这些定义为接口)。这也很适合编写单元测试。

正如您已经提到的,最大的问题是急切地加载关系,一旦您开始处理大量数据,这些关系就会非常迅速地加剧。解决方案可能是存储库应该知道每个实体的唯一标识符(即数据库中的主键),并且只能在实例化时获取它们,但我实际上还没有实现。