2

在没有ORM 框架支持的情况下,将域对象/实体与持久层结合起来的干净方法是什么?

我有域类/实体zcl_documentzcl_document_request(1:n)。我希望域类只包含核心域逻辑,没有基础设施,没有“助手”,没有持久性/加载机制。

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

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

为了实例化一个实体,通常每个实体都有一个公共静态create(工厂)方法,该方法采用“干净”结构,验证并生成其实例。与其他对象具有基本关联的实体更难create创建,因为也必须创建依赖对象。这些实体有自己的zcl_document_request_manager(承担命名)。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

这是可行的还是有一些气味?任何评论表示赞赏。

4

2 回答 2

2

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

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

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 ?根据我的经验,保存或丢弃某些内容的决定由正在运行的事务(顶级报告或正在运行的 UI)的控制器决定。但不应将其放入某种业务或服务方法/功能中。

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

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

于 2013-08-04T09:30:36.497 回答
0

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

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

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

于 2016-04-20T21:12:26.607 回答