DAO应该提供对单个相关数据源的访问,并根据业务模型的复杂程度返回完整的业务对象或简单的数据对象。无论哪种方式,DAO方法都应该与数据库相对应。
服务可以提供更高级别的接口,不仅可以处理业务对象,还可以首先访问它们。如果我从服务获取业务对象,那么该对象可能来自不同的数据库(和不同的DAO),它可能带有由HTTP请求生成的信息。它可能具有某些业务逻辑,将几个数据对象转换为单个健壮的业务对象。
通常,我创建DAO时会考虑到任何使用该数据库或一组业务相关数据的人都将使用它,除触发器、函数和存储过程之外,它实际上是数据库中最低级别的代码。
对于大多数情况而言,你不应该在DAO中包含不必要的数据访问方法,而是应该在服务层中进行更复杂的业务逻辑操作,组装来自不同查询的数据等。然而,如果你关心处理速度,服务层可能会将某个操作委派给DAO,即使它破坏了模型的完整性,这类似于C++程序员编写汇编代码加速某些操作。
如果您要在服务中使用实体管理器,则认为实体管理器就是您的DAO,因为它确实是。如果您需要删除某些冗余的查询构建,则不要在服务类中执行此操作,而是将其提取到使用实体管理器的类中,并将其作为DAO。如果您的用例非常简单,则可以完全跳过服务层,并在控制器中使用实体管理器或DAO,因为您的所有服务都将传递调用`getAirplaneById()`给DAO的`findAirplaneById()`。
更新 - 为了澄清下面的讨论,大多数情况下,在服务中使用实体管理器可能不是最佳决策,原因如评论中所述。但是,我认为,在以下情况下使用实体管理器是完全合理的:
1.服务需要与不同数据集交互
2.至少一个数据集已经有DAO
3.服务类驻留在需要一些持久性的模块中,该持久性足够简单,不需要自己的DAO
例如。
class PersonDao {
findPersonBySSN( long ssn )
}
class PetDao {
findPetsByAreaCode()
findCatByFullName()
}
class OurPortalPetLostAndFoundService {
notifyOfLocalLostPets( Person p ) {
Location l = ourPortalEntityManager.findSingle( PortalUser.class, p.getSSN() )
.getOptions().getLocation();
... use other DAO's to get contact information and pets...
}
}