2010-10-05 5 views
8

J'utilise une requête paramétrées pour insérer des valeurs dans une table Oracle, comme ceci:Pourquoi je reçois un ORA-01722 (numéro invalide)?

var q = "insert into MyTable(Field1, Field2...) values(:Field1, :Field2...)"; 
var cmd = new OracleCommand(q, conn); // conn is a pre-existing connection 
cmd.Parameters.Add("Field1", field1Val); 
cmd.Parameters.Add("Field2", field2Val); 
// etc... 
cmd.ExecuteNonQuery(); 

Cela a fonctionné très bien, mais tout à coup cela a cessé de travailler, et je reçois l'erreur Oracle ORA-01722 (Numéro invalide). J'ai vérifié les paramètres, et tous les nombres sont incontestablement des nombres valides. J'ai même substitué des valeurs factices pour n'importe quels nulls, et j'obtiens toujours l'erreur. J'ai essayé la même requête en SQL direct (en utilisant OraDeveloper Studio), et cela fonctionne, même avec les mêmes paramètres.

Comment puis-je suivre celui-ci?

EDIT: par demande dans les commentaires, voici la déclaration de create table:

CREATE TABLE ALPHA.VISITFINDINGS (
    ID NUMBER(12), 
    VISITID NUMBER(12) NOT NULL, 
    DESCRIPTION VARCHAR2(100), 
    CUSTOMIMAGE CLOB, 
    VISUALFINDINGSSECTIONMAPID NUMBER(12), 
    FINDINGSID NUMBER(12), 
    CONSTRAINT FK_VISITFINDINGS_AREA FOREIGN KEY (VISUALFINDINGSSECTIONMAPID) 
    REFERENCES ALPHA.VISUALFINDINGSSECTIONMAP(VISUALFINDINGSSECTIONMAPID), 
    CONSTRAINT FK_VISITFINDINGS_FINDINGS FOREIGN KEY (FINDINGSID) 
    REFERENCES ALPHA.FINDINGS(FINDINGSID), 
    CONSTRAINT FK_VISITFINDINGS_VISIT FOREIGN KEY (VISITID) 
    REFERENCES ALPHA.VISITS(VISITID), 
    CONSTRAINT PK_VISITFINDINGS PRIMARY KEY (ID)) 
TABLESPACE USERS 
STORAGE (
    INITIAL 64K 
    MAXEXTENTS UNLIMITED 
) 
LOGGING; 
+2

S'il vous plaît afficher l'instruction CREATE TABLE pour la table. Ma conjecture est que les valeurs que vous insérez sont plus grandes que ce qui est alloué pour le type de données. IE: la colonne est NUMBER (3) et vous essayez d'insérer 1 000. –

+0

Créer une déclaration de table publiée. –

Répondre

28

J'ai déjà donné un crédit de réponse, mais je pense qu'il vaut la peine de mentionner ici exactement la racine de mes problèmes, au cas où quelqu'un d'autre trouverait cet objet en cherchant une réponse à son propre problème.

Le problème est que la mise en œuvre C# de requêtes paramétrées pour Oracle contient un bogue sérieux et potentiellement dangereux - une « fosse dans le domaine public » réel:

Peu importe ce que vous nommez vos paramètres; ils doivent être ajoutés dans l'ordre dans lequel ils apparaissent dans la requête.

Voir plus here.

+2

Puisque c'est plus précis, vous devriez probablement supprimer check de ma réponse et marquer celui-ci à la place! – Rup

+0

@Rup - Vous mec juste, vous. ;) –

+3

Il est revendiqué dans l'autre thread ce n'est pas un bug, mais une fonctionnalité. Bien sûr, ce serait une fonctionnalité aussi dangereuse et inutile que d'être à la fois une fonctionnalité et un bug alors. Mais, ils disent que si vous définissez OracleCommand.BindByName = true, cela fonctionnera comme il se doit. –

5

Quand vous dites que vous avez vérifié les paramètres voulez-vous dire la collection Parameters sur la classe SqlCommand? Vous pourriez être en train de tomber sous le coup de this note on the SqlParameter page:

Soyez prudent lorsque vous utilisez cette surcharge du constructeur SqlParameter pour spécifier les valeurs des paramètres entiers. Parce que cette surcharge prend une valeur de type Object, vous devez convertir la valeur intégrale en un type d'objet lorsque la valeur est zéro, comme le montre l'exemple C# suivant. Copie

Parameter = new SqlParameter("@pname", Convert.ToInt32(0)); 

Si vous n'effectuez cette conversion, le compilateur suppose que vous essayez d'appeler la surcharge constructeur SqlParameter (string, SqlDbType).

Je vous suggère d'utiliser quelque chose comme

cmd.Parameters.Add(
    new SqlParameter("Field1", SqlDbType.Int32) { Value = field1Val }); 

au lieu de définir explicitement le type.

+3

L'OP utilise Oracle, pas SQL Server, donc ce serait OracleParameter ... mais votre réponse est toujours valable. Cependant, il n'explique pas pourquoi il a l'habitude de travailler ... –

+0

D'oh, désolé. Je ne me souvenais pas de la version d'Oracle, alors je voulais utiliser le nom de la classe de base, DbParameter.Certes, je ne suis pas sûr de savoir pourquoi cela aurait pu changer les choses à moins qu'il ne commence à passer des paramètres zéro. – Rup

+0

+1 C'était une bonne supposition, mais non - J'ai parcouru les paramètres réels en mode débogage et vérifié toutes leurs valeurs, et ils sont tous corrects. (Il était intéressant de noter que toutes les valeurs sont converties en chaînes - il semble absurde de convertir un nombre en chaîne sur le client, juste pour que vous puissiez le reconvertir du côté serveur!) –

0
command.BindByName = true; 

S'il vous plaît voir cette explination.

Questions connexes