我刚刚观察到一种奇怪的行为(当然Oracle可能会以这种方式表现,但它还不适合我的世界观):
我尝试在同一事务中的父表和子表中插入两行:
INSERT INTO V_Parent (ID, Name) VALUES (777, 'Hello World');
INSERT INTO T_Child (ParentID, Name) VALUES (777, 'Foo Bar');
Child表具有(ParentID) references Parent.ID
外键约束。
在第二个声明中,Oracle失败并显示错误消息“未找到父键。”
如果我禁用FK约束,它会起作用。我断言ParentID和Parent.ID匹配,我100%确定第一行在第二行之前成功执行。此外,我试图提交每个声明,这很好。
但是,作为我的代码示例中的前缀建议,第一个 INSERT实际上是在父表的视图上完成的。原因是我使用NHibernate并且映射使用后台视图(直到今天才引起任何问题)。
Q1:是否可以延迟在视图上插入,以便第二个语句失败?
Q2:我如何才能最好地解决这个问题?
详细信息:C#WinForms应用程序 - NHibernate - Oracle 10.2 - T_Child:我迟早会使用该表的视图,它还没有定义。
修改:根据评论更多详情:
<generator class="sequence">
)分配,并且是我示例中INSERT语句的一部分。我还验证了表格行中的结果ID与映射对象中保存的NHibernate匹配。*)嗯......让我想一想:由于我使用NHibernate会话来提交SQL查询,可能是NHibernate以不同于我告诉它的顺序执行它们吗? < / p>
我会对此进行调查。 =&gt;看来是这样,看看我自己的答案。
这是实际代码的样子:
ISession session = this.DAOFactory.NHibernateHelper.SessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
try
{
// parent.ID == 0
session.SaveOrUpdate(parent);
// parent.ID == 777 (for example)
ISQLQuery query = session.CreateSQLQuery(
"INSERT INTO T_CHILD (PARENT_ID, NAME) VALUES (:parentId, :name)");
query.SetDecimal("parentId", parent.ID);
query.SetDecimal("name", "Foo Bar");
query.ExecuteUpdate(); // Fails with ORA-Exception
tx.Commit();
}
catch (Exception)
{
tx.Rollback();
throw;
}
finally
{
session.Close();
}
答案 0 :(得分:1)
如果视图为already updateable,则无需定义INSTEAD OF触发器。在与基表具有简单关系的视图中插入将表现为插入基表 - 考虑:
SQL> CREATE TABLE t (a NUMBER, b NUMBER, c NUMBER);
Table created
SQL> CREATE VIEW v AS SELECT a, b FROM t;
View created
SQL> INSERT INTO v VALUES (1,2);
1 row inserted
SQL> SELECT * FROM t;
A B C
---------- ---------- ----------
1 2
对于插入问题,您可能在基表上有一个BEFORE INSERT触发器(序列填充了id
colomn)。
答案 1 :(得分:1)
我知道了。
正如我的问题更新中所述,似乎NHibernate会话混合了SQL语句的顺序。为了解决这个问题,我添加了以下代码行:
session.SaveOrUpdate(parent);
session.Flush();
// (...)
query.ExecuteUpdate();