java Hibernate在Servlet环境中的使用
我试图创建一个域对象,它以只读方式包含对象,但能够修改它指向的对象
因此,在下面的示例中,我希望Hibernate处理填充Account和Category对象,但我不想更新这些对象。然而,我可能希望更改我希望费用指向的账户或类别
换句话说,我可能希望更新费用表上的account_id或category_id,但我永远不想用我对费用对象中包含的account或category对象所做的更改来更新account或category表
@Entity
@Table(name = "expense")
public class Expense {
@Id
@GeneratedValue
private long id;
private String name;
private BigDecimal amount;
@OneToOne
@JoinColumn(name = "id", referencedColumnName = "category_id")
//From table called category
private Category category;
@OneToOne
@JoinColumn(name = "id", referencedColumnName = "account_id")
//From table called account
private Account account;
我是完全误用了Hibernate还是它不是正确的工具?我应该用@SQLUpdate和@SQLInsert定义自己的sql吗
应用程序的一般流程是标准的web应用程序
- 从数据库加载数据
- 在表格上显示
- 收集用户所做的更改
- 坚持这些变化
谢谢
# 1 楼答案
这有点偏离了冬眠的意图。对持久对象的更改应该是持久的。如果你不想保存它们的状态,就不要更改它们!解释并更好地理解你为什么想要这种行为可能会帮助你找到解决方案(或者帮助我们帮助你)
一个选项是,在返回Expense对象之前,分离/逐出不希望在数据访问层内更改的映射对象。然后,只要没有级联打开,对它们所做的更改就不会被保存。在我看来,这会导致其他程序员出现“令人惊讶”的行为
另一个选择是以无会话方式使用hibernate。每个调用都是自己的原子数据库操作,所有对象在返回后都被分离。然后,只有显式调用saveOrUpdate的实体才会保存到数据库中。你可以在Hibernate参考文档中学习如何配置Hibernate以这种方式工作,不过我也不知道,如果你不想模仿你正在提升的某个遗留系统的行为,你为什么要这样做
最后一点是,在一次会议中,你需要了解你通过呼叫费用获得的类别。getCategory()通常是通过调用会话获得的实际对象。获取(Category.class,123)。因此,如果在同一个会话中有两种访问它的方法,那么如果您试图手动管理它,就很容易失去对其实体状态的跟踪
编辑:
啊哈!现在它更有意义了
如果你做的是纯粹粗糙的网页表单屏幕,你不需要担心太多。只要没有任何级联,当合并回分离的
Expense
对象时,Category
和Account
上的更改就不会出现在数据库中。你可以把其他字段都清空,只要id还在,你就可以了。(假设你没有其他类似级联验证的东西会为此哭泣。)有两种基本模式可以更好地处理这个问题
一种是将
Expense
对象放在用户的web会话上。这样,您就拥有了整个内容,您的web数据绑定框架只需要将表单实际更改的字段绑定回它。原始的Category
和Account
仍然存在(或它们的代理),活页夹不需要咀嚼它们。缺点当然是添加服务器端状态,以及需要清理它二是注册实际进入数据库的数据绑定,并在web绑定期间获取映射实体。因此,表单中实际出现的只是映射字段的ID,绑定器将为您获取并放置完整的对象。缺点可能是不需要来回访问数据库,但积极的二级缓存可以解决这一问题(假设类别几乎从未更改,帐户很少更改)
如果您目前正在通过在DAO中创建和处理会话,以基本上无会话的方式使用hibernate,那么您可能还需要查看OpenSessionInView/OpenEntityManagerView模式