我有一个C#应用程序,必须按层次顺序插入一条父记录和至少四条子记录。 IOW,父合同适用于一个或多个地点,每个地点有一个或多个物品,每个物品有一个或多个服务,每个服务都有一个或多个要求。应用程序首先获取一组Oracle序列号,每个记录的每个表序列中都有一个序列号。无论出于何种原因(遗留数据库),每条记录不仅包含其父级序列号,还包含合同序列号。
因此,代码开始一个事务,插入带有父级序列号的父代,然后尝试插入位置记录 - 已经填充了父编号作为FK,以及它自己的表序列号。但是,我收到一个Oracle-02291错误,因为找不到父编号而违反了FK。
INSERT into Contracts (contract_sequence_number, ...) values (10437, ...);
INSERT into Locations (location_sequence_number, contract_sequence_number, ...)
values (23733, 10437, ...);
...
我猜这是因为父母尚未提交,因此无法使用。但是,如果任何子记录失败,我无法提交父级,因此在子插入之前提交。
我知道这是一个常见的场景,答案必须是pre-noob。但是,到目前为止,我发现的所有答案都暗示父序列号在“表中”中找到,以便满足FK。
对我如何解决这个问题的任何想法都非常感谢。
兰迪
答案 0 :(得分:1)
子插入将看到任何已提交或先前已由同一事务插入的父级(无论是否已提交)。
要验证的一件事是父项的插入是否自动导出主键值(例如通过触发器)。
也就是说,您发出声明 INSERT into Contracts(contract_sequence_number,...)values(10437,...);
但触发器会从序列中确定一个新的contract_sequence_number,并实际为其提供主键10438(或其他)。
另一个问题可能是任何ORM层通过不以正确的顺序发出插入或使用不同的连接从池中为单个“事务”来解决问题。
同时检查父项的插入没有返回错误。
尝试通过传统客户端(例如SQL * Plus)进行示例事务,看看是否有效。如果子插入失败,只需从合同中查询最近的条目(例如,contract_sequence_number> 10400)并查看插入是否成功。
答案 1 :(得分:1)
将您的fk约束设置为deferrable initially deferred
。
此外,您需要在单个事务中执行两个/所有插入。如果你正在使用ODAC for C#,那么首先开始OracleTransaction,进行插入,然后是commit()和dispose()。确保在catch块中为事务调用rollback()和dispose()。
有关Oracle数据访问组件的PDF版本(11g),请参阅here。
希望有所帮助
答案 2 :(得分:0)
是使用PRAGMA_AUTONOMOUS_TRANSACTION设置完成的任何插入吗?在我看来,挂起的提交应该对整个交易可见。
哦另一个想法 - 如果插入在PRE触发器中,请尝试将它们移动到POST触发器。
答案 3 :(得分:0)
我建议您检查延迟约束,这些约束会在您将数据提交到数据库时检查值,因此您可以避免FK未找到错误
答案 4 :(得分:0)
谢谢大家的意见。原来(我怀疑)这是我的坏事。事实证明,有两个非常相似的模式,我使用的连接可以访问两者。两个模式都具有相同名称的表。由于我不清楚的原因,父母插入一个schmea,但孩子试图插入另一个模式。当然它无法解决PK / FK关系!
再次,谢谢。