为什么 DbCommandBuilder (Oracle) 为 UpdateCommand 生成奇怪的 WHERE 子句?

发布于 2024-08-26 04:09:23 字数 1716 浏览 2 评论 0原文

我在oracle db中有一个表HolidayHome,它在Id上有唯一的数据库索引(我没有在代码中以任何方式为适配器/表/数据集指定这一点,不知道我是否应该/可以)。

DbDataAdapter.SelectCommand 是这样的:

SELECT Id, ExtId, Label, Location1, Location2, Location3, Location4, 
ClassId, X, Y, UseType 
FROM HolidayHome

但是 DbCommandBuilder 生成的 UpdateCommand 有非常奇怪的 where 子句:

UPDATE HOLIDAYHOME SET ID = :p1, EXTID = :p2, LABEL = :p3, LOCATION1 = :p4, 
LOCATION2 = :p5, LOCATION3 = :p6, LOCATION4 = :p7, CLASSID = :p8, X = :p9, 
Y = :p10, USETYPE = :p11 
WHERE ((ID = :p12) AND ((:p13 = 1 AND EXTID IS NULL) OR (EXTID = :p14)) AND 
((:p15 = 1 AND LABEL IS NULL) OR (LABEL = :p16)) AND 
((:p17 = 1 AND LOCATION1 IS NULL) OR (LOCATION1 = :p18)) AND 
((:p19 = 1 AND LOCATION2 IS NULL) OR (LOCATION2 = :p20)) AND 
((:p21 = 1 AND LOCATION3 IS NULL) OR (LOCATION3 = :p22)) AND 
((:p23 = 1 AND LOCATION4 IS NULL) OR (LOCATION4 = :p24)) AND 
(CLASSID = :p25) AND (X = :p26) AND (Y = :p27) AND (USETYPE = :p28))

所有这些具有 like: 的字段

((:p17 = 1 AND LOCATION1 IS NULL) OR (LOCATION1 = :p18))

在 oracle db 中都是这样定义的:

LOCATION1 VARCHAR2(30)

所以它们允许空值。

代码如下所示:

        static bool CreateInsertUpdateDeleteCmds(DbDataAdapter dataAdapter)
        {
            DbCommandBuilder builder = _trgtProvFactory.CreateCommandBuilder();
            builder.DataAdapter = dataAdapter;

            // Get the insert, update and delete commands.
            dataAdapter.InsertCommand = builder.GetInsertCommand();
            dataAdapter.UpdateCommand = builder.GetUpdateCommand();
            dataAdapter.DeleteCommand = builder.GetDeleteCommand();
        }

该怎么办? UpdateCommand 完全是疯狂的。

谢谢&最好的问候:马蒂

I have a table HolidayHome in oracle db which has unique db index on Id (I haven't specified this in the code in any way for adapter/table/dataset, don't know if i should/can).

DbDataAdapter.SelectCommand is like this:

SELECT Id, ExtId, Label, Location1, Location2, Location3, Location4, 
ClassId, X, Y, UseType 
FROM HolidayHome

but UpdateCommand generated by DbCommandBuilder has very weird where clause:

UPDATE HOLIDAYHOME SET ID = :p1, EXTID = :p2, LABEL = :p3, LOCATION1 = :p4, 
LOCATION2 = :p5, LOCATION3 = :p6, LOCATION4 = :p7, CLASSID = :p8, X = :p9, 
Y = :p10, USETYPE = :p11 
WHERE ((ID = :p12) AND ((:p13 = 1 AND EXTID IS NULL) OR (EXTID = :p14)) AND 
((:p15 = 1 AND LABEL IS NULL) OR (LABEL = :p16)) AND 
((:p17 = 1 AND LOCATION1 IS NULL) OR (LOCATION1 = :p18)) AND 
((:p19 = 1 AND LOCATION2 IS NULL) OR (LOCATION2 = :p20)) AND 
((:p21 = 1 AND LOCATION3 IS NULL) OR (LOCATION3 = :p22)) AND 
((:p23 = 1 AND LOCATION4 IS NULL) OR (LOCATION4 = :p24)) AND 
(CLASSID = :p25) AND (X = :p26) AND (Y = :p27) AND (USETYPE = :p28))

all these fields that have like:

((:p17 = 1 AND LOCATION1 IS NULL) OR (LOCATION1 = :p18))

are defined in oracle db like this:

LOCATION1 VARCHAR2(30)

so they allow null values.

the code looks like this:

        static bool CreateInsertUpdateDeleteCmds(DbDataAdapter dataAdapter)
        {
            DbCommandBuilder builder = _trgtProvFactory.CreateCommandBuilder();
            builder.DataAdapter = dataAdapter;

            // Get the insert, update and delete commands.
            dataAdapter.InsertCommand = builder.GetInsertCommand();
            dataAdapter.UpdateCommand = builder.GetUpdateCommand();
            dataAdapter.DeleteCommand = builder.GetDeleteCommand();
        }

what to do? The UpdateCommand is utter madness.

Thanks & Best Regards: Matti

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

纵性 2024-09-02 04:09:23

我真的不知道这些 ((:px = 1 AND XXX IS NULL) OR (XXX = :py)) 的目的,但是 CommandBuilder 确实生成了一个 where 子句来检查正在更新的行是否已更改,因为您加载它。例如,如果您加载带有值 (c1, c2, c3,...,cn) 的行 R1,并使用 c3' 更改 c3 的值,则更新命令文本有一个 where 子句,用于检查所有原始值行(例如,其中 C1 = c1 且 C2 = c2 且...)。如果更新命令影响 0 行,则意味着其他人在您加载该行和更新该行之间的时间内更新了该行,并且会引发 DbConcurrencyException。我知道你可以改变这种行为(不记得具体如何改变)。

这就是更新命令中Where 子句的主要原因。

I really don´t know the purpose of those ((:px = 1 AND XXX IS NULL) OR (XXX = :py)), but the CommandBuilder does generate a where clause to check if the row being updated has been changed since you loaded it. For example if you load a row R1 with values (c1, c2, c3,...,cn) and you change the value of c3 with c3' then the update command text has a where clause that checks for all the original values of the row (e.g. where C1 = c1 and C2 = c2 and ...). If the update command affects 0 rows it means that someone else has updated that row in the time between you loaded it and the time you updated it, and it throws a DbConcurrencyException. I know that you can change that behavior (don´t remember exactly how).

So that is the main reason of the Where clause in the update command.

祁梦 2024-09-02 04:09:23

问题与数据库 NULL 在 DataTable 中的表示方式以及如何测试数据库中列的值是否仍然为 NULL 有关。

在 SQL 中,NULL 不是一个值,它是一种状态。所以你不能测试NULL 的 sql 列如下:WHERE MyColumn = NULL,此测试将始终返回 false,

因此您需要在 WHERE 中进行两个不同的测试来检查实际列状态是否仍然是相同的。

DataRows 保留旧值和新值,因此更新命令应该是:

UPDATE MyTable 
SET KeyColumn = KeyDatacolumn.NewValue, OtherColumn = OtherDataColumn.NewValue
WHERE KeyColumn = KeyDatacolumn.OldValue AND OtherColumn = OtherDataColumn.OldValue

请注意,OtherColumn 上的 WHERE 条件只是为了避免覆盖其他人对同一记录的更新

但是,如前所述,如果 OtherColumn可以为空,我们不能简单地测试 WHERE OtherColumn = OtherDataColumn.OldValue

因此更新命令将是:

UPDATE MyTable 
SET KeyColumn = KeyDatacolumn.Value, OtherColumn = OtherDataColumn.NewValue
WHERE
    (KeyColumn = KeyDatacolumn.OldValue) AND  
    (
        (OtherColumn = OtherDataColumn.OldValue)
        OR
        (
            (OtherDataColumn.OldValue.Equals(DBNull))
            AND
            (OtherColumn IS NULL)
        )
    )

您可以读取 OtherColumn 上的条件,例如“其中 OtherColumn 的值与 之前的值相同OR (它是 NULL AND 它仍然是 NULL )”

因此,对于可空列,每列将使用 2 个不同的参数,第一个参数将作为 DataColumn 传递。 OldValue.Equals(DBNull) 和第二个将作为 IIF(DataColumn.OldValue.Equals(DBNull), "NULL", DataColumn.OldValue) 传递,

我希望是有什么帮助
问候

The problem is related to how database NULLs are represented in your DataTable and how to test if the value of column in the database is still NULL

In SQL, NULL is not a value, it is a state.. so you can't test a sql column for NULL like this: WHERE MyColumn = NULL, this test will always return false

so you need two different test in your WHERE to check if actual column state is still the same.

The DataRows keeps both old and new values so the update command should be:

UPDATE MyTable 
SET KeyColumn = KeyDatacolumn.NewValue, OtherColumn = OtherDataColumn.NewValue
WHERE KeyColumn = KeyDatacolumn.OldValue AND OtherColumn = OtherDataColumn.OldValue

Note that the WHERE condition on OtherColumn is needed only to avoid to overwrite someone else's updates to same record

But, as said before, if OtherColumn is nullable, we can't simply test WHERE OtherColumn = OtherDataColumn.OldValue

so the update command will be:

UPDATE MyTable 
SET KeyColumn = KeyDatacolumn.Value, OtherColumn = OtherDataColumn.NewValue
WHERE
    (KeyColumn = KeyDatacolumn.OldValue) AND  
    (
        (OtherColumn = OtherDataColumn.OldValue)
        OR
        (
            (OtherDataColumn.OldValue.Equals(DBNull))
            AND
            (OtherColumn IS NULL)
        )
    )

You can read the condition on OtherColumn like "where OtherColumn has the same value it had before OR (it was NULL AND it is still NULL )"

So, for nullable columns will be used 2 different parameters for each column, the 1st one will be passed as DataColumn.OldValue.Equals(DBNull) and the 2nd one will be passed as IIF(DataColumn.OldValue.Equals(DBNull), "NULL", DataColumn.OldValue)

I hope to have been of any help
regards

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文