2010-03-25 3 views
1

J'ai une table HolidayHome dans oracle db qui a un index db unique sur Id (je ne l'ai pas spécifié dans le code pour adapter/table/dataset, ne sais pas si je devrais/peut).pourquoi DbCommandBuilder (Oracle) produit étrange WHERE-clause à UpdateCommand?

DbDataAdapter.SelectCommand est comme ceci:

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

mais UpdateCommand généré par DbCommandBuilder a très étrange clause 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)) 

tous ces domaines qui ont comme:

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

sont définis dans Oracle db comme ceci:

 
LOCATION1 VARCHAR2(30) 

afin qu'ils permettent des valeurs nulles.

le code ressemble à ceci:

 
     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(); 
     } 

quoi faire? Le UpdateCommand est une folie absolue.

Merci & Cordialement: Matti

Répondre

2

Je ne pas vraiment connaître le but de ces ((: px = 1 ET XXX IS NULL) OR (XXX =: py)), mais le CommandBuilder ne génère une where clause pour vérifier si la ligne mise à jour a été modifiée depuis que vous l'avez chargée. Par exemple, si vous chargez une ligne R1 avec des valeurs (c1, c2, c3, ..., cn) et que vous modifiez la valeur de c3 avec c3 ', le texte de la commande de mise à jour contient une clause where qui vérifie toutes les valeurs d'origine la rangée (par exemple où C1 = c1 et C2 = c2 et ...). Si la commande de mise à jour affecte 0 ligne, cela signifie que quelqu'un d'autre a mis à jour cette ligne entre le moment où vous l'avez chargé et le moment où vous l'avez mise à jour, et elle lance une exception DbConcurrencyException. Je sais que vous pouvez changer ce comportement (ne vous rappelez pas exactement comment).

Donc, c'est la raison principale de la clause Where dans la commande de mise à jour.

+0

oui. Je sais ce qu'est une clause where. edit: Personnellement, je pense que répondre «je ne sais vraiment pas ...» n'est pas une bonne pratique puisque maintenant la question n'est plus sans réponse. –

+0

L'expression "Je ne sais vraiment pas le but ..." est parce que dans ce cas particulier, je ne sais pas ce que sont les types de colonnes, si elles sont valables, ni les valeurs des paramètres. Je n'ai pas expliqué ce qu'est une clause where, je vous ai expliqué pourquoi DbCommandBuilder génère une clause where qui peut ne pas apparaître comme la clause where typique lorsque vous effectuez une mise à jour. – uvita

+0

vous avez raison, mais le savait déjà. de toute façon désolé à ce sujet. la chose que je ne sais toujours pas est celle-ci "((: p15 = 1 ET LABEL EST NUL) OU (LABEL =: p16))" - business. Tous ces champs acceptent une valeur nulle. edit: a donné un u-up vote. –

0

Le problème est lié à la façon dont la base de données NULLs sont représentées dans votre DataTable et comment tester si la valeur de la colonne dans la base de données est toujours NULL

Dans SQL, NULL est pas une valeur, il est un état. donc vous ne pouvez pas tester une colonne sql pour NULL comme ceci: WHERE MyColumn = NULL, ce test retournera toujours faux

alors vous avez besoin de deux tests différents dans votre WHERE pour vérifier si l'état de la colonne est toujours le même.

DataRows conserve les anciennes et les nouvelles valeurs de sorte que la commande de mise à jour doit être:

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

Notez que la condition WHERE sur OtherColumn est nécessaire uniquement pour éviter d'écraser de quelqu'un d'autre mises à jour de même enregistrement

Mais, comme dit précédemment, si OtherColumn est annulable, nous ne pouvons pas simplement tester WHERE OtherColumn = OtherDataColumn.OldValue

de sorte que la commande de mise à jour sera:

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) 
     ) 
    ) 

Vous pouvez lire la condition sur OtherColumn comme « où OtherColumn a la même valeur qu'il avait avant OR (il était NULL AND il est encore NULL) »

Ainsi, pour les colonnes nullables seront utilisées 2 différentes paramètres pour chaque colonne, la 1ère sera passé comme DataColumn.OldValue.Equals(DBNull) et le 2e sera passé comme IIF(DataColumn.OldValue.Equals(DBNull), "NULL", DataColumn.OldValue)

J'espère avoir été d'aucune aide
concernant

Questions connexes