我正在开发一个新的Java Web应用程序,并且正在探索保存数据的新方法(对我来说是新的!)。我大多数都具有JPA和Hibernate的经验,但是,除了简单的情况之外,我认为这种完整的ORM可能会变得非常复杂。另外,我不太喜欢和他们一起工作。我正在寻找一个新的解决方案,可能更接近SQL。
我目前正在研究的解决方案:
但是,与Hibernate相比,我担心的是这些解决方案有两个用例。我想知道这些用例的推荐模式是什么。
Person
Address
City
name
从人员实体开始,访问城市名称的完整路径为:
person.address.city.name
现在,假设我PersonService使用以下方法从加载了Person实体:
PersonService
public Person findPersonById(long id) { // ... }
使用Hibernate,Person可以根据需要延迟加载与关联的实体,因此可以访问person.address.city.name并确保我可以访问此属性(只要该链中的所有实体都不为空)。
但是使用我正在研究的3个解决方案中的任何一个,它都更加复杂。使用这些解决方案,建议使用哪种模式来处理该用例?首先,我看到3种可能的模式:
但是我看到的这个解决方案的问题是,可能还有一些其他代码需要访问来自该实体的 其他 实体/属性路径Person。例如,也许某些代码需要访问person.job.salary.currency。如果要重用findPersonById()已有的方法,则SQL查询将需要加载更多信息!不仅关联address->city实体,而且关联job->salary实体。
person.job.salary.currency
findPersonById()
address->city
job->salary
现在,如果还有其他 10 个地方需要从人员实体开始访问其他信息,该怎么办?我是否应该始终热切地加载 所有 可能需要的信息?或者也许有12种不同的服务方法来加载人实体?:
findPersonById_simple(long id) findPersonById_withAdressCity(long id) findPersonById_withJob(long id) findPersonById_withAdressCityAndJob(long id) ...
但是,每当我使用一个Person实体时,我就必须知道它已经加载了什么,没有加载了什么……可能会很麻烦,对吧?
在实体的getAddress()getter方法中Person,是否可以进行检查以查看地址是否已经加载,如果没有,则延迟加载它?这是现实生活中经常使用的模式吗?
getAddress()
还有其他模式可用于确保我可以从加载的模型访问所需的实体/属性吗?
我希望能够Person使用此PersonService方法保存实体:
public void savePerson(Person person) { // ... }
如果我有一个Person实体并且要更改person.address.city.name为其他实体,那么City当我保存该实体时,如何确保该实体的修改将得以保留Person?使用Hibernate,可以很容易地将保存操作 级联 到关联的实体。我正在研究的解决方案如何?
我应该使用某种 肮脏的 标记来知道在保存人时还必须保存哪些关联的实体吗?
还有其他已知模式可用于处理此用例吗?
更新 :有一个讨论有关在JOOQ论坛这个问题。
当不使用真正的ORM时,这种问题很典型,并且没有灵丹妙药。对于使用iBatis(myBatis)的(不是很大的)Web应用程序来说,一种对我有用的简单设计方法是使用两层持久性:
愚蠢的底层:每个表都有其Java类(POJO或DTO),其 字段直接映射到表的column 。假设我们有一个PERSON表,其中的一个ADDRESS_ID字段指向一个ADRESS表;然后,我们将有一个PersonDb仅包含addressId(整数)字段的类;我们没有 personDb.getAdress()办法,只有平原personDb.getAdressId()。因此,这些Java类非常笨拙(它们对持久性或相关类一无所知)。相应的PersonDao类知道如何加载/持久化此对象。使用iBatis + iBator(或MyBatis + MYBatisGenerator)之类的工具可以轻松创建和维护该层。
PERSON
ADDRESS_ID
ADRESS
PersonDb
addressId
personDb.getAdress()
personDb.getAdressId()
PersonDao
包含 丰富域对象的 更高层:这些 对象 通常是上述POJO 的 图形 。这些类还具有通过调用相应的DAO来加载/保存图形(可能很懒惰,可能带有一些脏标志)的智能。但是,重要的是,这些丰富的域对象不是一对一地映射到POJO对象(或DB表),而是使用 域用例 。确定每个图的“大小”(它不会无限增长),并且像特定类一样从外部使用。因此,并不是说您有一个丰富的Person类(带有一些不确定的相关对象图)被用于多个用例或服务方法。相反,您有几个丰富的类PersonWithAddreses, PersonWithAllData…每个人都包装了一个特定的,受限制的图,并具有自己的持久逻辑。这似乎效率低下或笨拙,在某些情况下可能是这样,但是经常发生这种情况,当您需要保存完整的对象图时,用例实际上受到限制。
PersonWithAddreses
PersonWithAllData
另外,对于表格报告之类的东西((特定的SELECTS返回一堆要显示的列)),您将不会使用上述内容,而会使用直截了当的POJO(甚至可能是Maps)