Oracle 强制Hibernate在插入之前发出删除以避免违反唯一约束?
背景: 我们的桌子是:Oracle 强制Hibernate在插入之前发出删除以避免违反唯一约束?,oracle,hibernate,ora-00001,deferrable-constraint,Oracle,Hibernate,Ora 00001,Deferrable Constraint,背景: 我们的桌子是: BOND_PAYMENTS (BOND_PAYMENT_ID, BOND_NUMBER, PAYMENT_ID) 对BOND_PAYMENT_ID有主键约束,对(BOND_编号、PAYMENT_ID)有唯一约束 该应用程序使用Hibernate,允许用户查看与特定债券相关的所有付款;它允许他们创建新链接,并删除现有链接。一旦他们在页面上做了所有想要的更改,他们点击“保存”,Hibernate就会神奇地在数据库上运行所需的SQL。显然,Hibernate计算出哪些记录需要
BOND_PAYMENTS (BOND_PAYMENT_ID, BOND_NUMBER, PAYMENT_ID)
对BOND_PAYMENT_ID有主键约束,对(BOND_编号、PAYMENT_ID)有唯一约束
该应用程序使用Hibernate,允许用户查看与特定债券相关的所有付款;它允许他们创建新链接,并删除现有链接。一旦他们在页面上做了所有想要的更改,他们点击“保存”,Hibernate就会神奇地在数据库上运行所需的SQL。显然,Hibernate计算出哪些记录需要删除,哪些记录需要插入,其余的记录保持不变。不幸的是,它先进行插入,然后进行删除
如果用户删除了一个指向付款的链接,然后改变主意,重新插入指向同一付款的链接,Hibernate会很高兴地尝试插入链接,然后删除它。由于这些插入/删除是作为单独的SQL语句运行的,Oracle会在第一次插入时立即验证约束,并发出违反的ORA-00001唯一约束
我们只知道两种选择:
ALTER TABLE bond_payments ADD
CONSTRAINT bond_payment_uk UNIQUE (bond_number, payment_id)
DEFERRABLE INITIALLY DEFERRED;
缺点是,为监控此约束而创建的索引现在是非唯一索引,因此查询效率可能会有所降低。我们已经决定,这对这个特殊的案件没有那么大的损害。另一个缺点(Gary建议)是它可能会遇到特定的Oracle错误——尽管我相信,由于应用程序的工作方式,我们将免疫(至少,大部分免疫)
是否有其他的选择要考虑? < P>从您所描述的问题,不清楚您是否有实体“代码>债券支付<代码>,或者如果您有一个<代码>债券直接链接到<代码>付款< /代码>。现在,我假设您通过
BondPayment
在Payment
和Bond
之间建立了链接。在这种情况下,Hibernate做的是正确的,您需要在应用程序中添加一些逻辑来检索链接并将其删除(或更改)。大概是这样的:
bond.getBondPayment().setPayment(newPayment);
BondPayment bondPayment = new BondPayment();
bondPayment.setPayment(newPayment);
bondPayment.setBond(bond);
bond.setBondPayment(bondPayment);
您可能正在做这样的事情:
bond.getBondPayment().setPayment(newPayment);
BondPayment bondPayment = new BondPayment();
bondPayment.setPayment(newPayment);
bondPayment.setBond(bond);
bond.setBondPayment(bondPayment);
在第一种情况下,会保留BondPayment.id
,您只需为其更改付款。在第二种情况下,它是一个全新的BondPayment
,它将与数据库中的现有记录冲突
我说Hibernate做的是正确的,因为它威胁到作为“常规”实体的BondPayment,其生命周期由应用程序定义。这与在登录
上有唯一约束的用户
相同,您尝试插入第二条记录,该记录具有重复的登录
。Hibernate将接受(它不知道数据库中是否存在登录名
),而您的数据库将拒绝 您是否介意提供一些代码,比如:受影响的实体,sf.openSession和session.close之间的代码?顺便说一下:Hibernate以前做过插入,但只为实体插入,不为关系插入。关系(集合)的插入操作是第五步:-)我自己不是Hibernate编码员-我是Oracle的家伙-我会看看常驻Java开发大师能否提供一些细节:)你说得对,它的Bond
-1:m-BondPayment
-m:1-Payment
。因此,你必须按照我提到的方式处理它,这将触发BondPayments表中的一个选择,并对其进行后续更新。我不确定他们编写应用程序的方式是否允许这样做。我相信这一切都是在页面上自动完成的,当用户添加BondPayment时,必须执行一些自定义代码,搜索用户刚刚删除的旧BondPayment,并将其更改为更新,这听起来似乎比他们准备为“正常工作”的东西做的工作要多:)接受。我们已经使约束立即生效,从而解决了这个问题,因为开发人员已经修改了前端以自动“回收”现有行,而不是删除然后插入它们。