将DAO的某些部分委托给另一个DAO是否更好,以便它更具可读性和紧凑性?重复代码少了吗?
实施例
MainProject.php
因为我读过DAO应该:
这是否意味着我必须在每个DAO中重复相同的过程而不是委托,因此它将独立于其他DAO?
答案 0 :(得分:5)
常见的事情是使用服务来调用不同的daos注入数据的需要。在这种情况下,这似乎更合乎逻辑,因为它实际上是业务逻辑,因此最好在数据库层中尽可能少地使用它
答案 1 :(得分:2)
简答:否
根据模式,可以被称为Table Module的DAO限于每个类一个表表模块使用数据库中每个表的一个类来组织域逻辑,并且类的单个实例包含将对数据起作用的各种过程
但是,这些可以用外观包裹或Transaction Script来管理多个Table Modules之间的互动。
事务脚本主要将所有这些逻辑组织为一个过程,直接调用数据库或通过瘦数据库包装器。每个事务都有自己的事务脚本,尽管常见的子任务可以分解为子过程。
答案 2 :(得分:1)
在您的示例中,此处的主要问题是您使用SemesterEnrollmentDAO搜索其他实体。
绝对您是否需要检索Student
权利,以便稍后检索SemesterEnrollment
?
如果您的实体之间有很好的设计关系,那么您可以使用SemesterEnrollment
查询studentId
,而无需先检索Student
实体。
实施例
Query query = em.createQuery("SELECT e FROM SemesterEnrollment e JOIN e.student s "
+ "WHERE s.studentId = :studentId");
这样就可以避免委托和1 + N问题,如果你真正需要检索的是SemesterEnrollment
实体,那么SemesterEnrollmentDAO
也是如此。
答案 3 :(得分:1)
你知道经验法则,但没有人解决原因。
DAO的作用是包含一组CRUD函数。每种方法都是针对事务数据存储(通常是数据库)的一些操作。如果将DAO调用链接在一起,则最终会将事务链接在一起。这对READS来说不是什么大问题;但是当你进入WRITES时,它会变得混乱。
例如,您有一个复合的EnrollmentRecord对象。它包含StudentRecord,学生注册的每个班级的SectionRecords,以及每个SectionRecord链接到ClassRecord。如果调用createEnrollement(EnrollmentRecord),它也可以链接出来以包含EnrollmentRecord中的其他对象。
如果您可以创建StudentRecord会发生什么,但某些SectionRecords或ClassRecords会失败?回滚?你离开学生,但删除任何注册的课程?如果一个注册的课程失败了,你会把它们全部卷回来吗?
一旦开始协调事务,您现在正在混合业务逻辑。业务规则将随着时间和情况而变化;但注册,学生,科和班级的基本CRUD不会。
使用服务对象聚合DAO。复合数据对象应由协调所有DAO调用的服务进行管理(事件多次调用单个DAO!)这允许您将业务/事务逻辑与CRUD逻辑分开,并使每个层保持模块化和可重用。
使用服务层的另一个重要原因是实体模型通常是双向的。您可以加载学生,然后获取所有课程。您可以获取课程并加载所有学生。随着对象模型的增长,您将很容易获得循环关系。
例如,您有objectA,其中包含objectBs的集合。你的loadA方法调用loadB。
将来有人会添加扩展loadB以委托给LoadC。后来,有人说如果我能加载一个C'那将会很棒。并知道它链接到哪个'因此,他们将loadC扩展为委托给loadA,后者返回一个' A'宾语。现在整个事情爆发了,没有追踪整个循环路径就不明显了。
使用服务图层来协调复合对象。从CRUD逻辑中分离组合逻辑可以更容易地避免循环引用和管理复杂的对象图。
所以DAO调用DAO本身并不邪恶;但是,这种捷径很容易导致处理CRUD,业务/事务逻辑和复杂对象图规则的巨型DAO方法。从服务中清除DAO有助于防止这种情况发生。
答案 4 :(得分:0)
根据经验,DAO应该关注检索/持久化数据,因此任何业务逻辑或数据转换都会简单地驻留在单独的业务层中。在您提供的示例中,可以询问如果对StudentDAO的调用失败,则会发生什么,因为根本没有数据。这是在服务层中解决的问题。 在您的示例中,EnrollmentDAO可以转换为EnrollmentService。