2013-07-23 4 views
0

Je migre notre application Delphi XE2 de MSSQL (en utilisant des composants ADO) à PostgreSQL en utilisant UniDAC.PostgreSQL serial (autoincrement) avec UniDac sur Delphi XE2

Dans la base de données, il existe quelques champs de type serial (auto-incrémentation). Lorsque j'ajoute un enregistrement, je ne mets aucune donnée dans ce champ d'auto-incrémentation. Formellement, avec MSSQL/ADO cela fonctionne automatiquement, mais maintenant j'ai une exception.

Le code:

aqrMsgs.Append; 
aqrMsgsUser_From.AsInteger := UserId; 
aqrMsgsUser_To.AsString := UserIds[I]; 
aqrMsgsSubject.AsString := Trim (edtSubject.Text); 
aqrMsgsContents.AsString := mmoContents.Text; 
aqrMsgsIsDone.AsBoolean := False; 
aqrMsgs.Post; 

Et l'exception est:

Exception

'id' Le champ est TIntegerField, pas TAutoIncrementField. Par ailleurs, si j'utilise DBGrid edit (exactement, j'utilise ExpressQuantumGrid), pour ajouter des enregistrements à une autre table avec la même structure, tout fonctionne bien.

Comment est-ce possible de le résoudre? Merci.

Répondre

1

1) Lorsque vous créez un champ avec le type de série, serveur PostgreSQL crée automatiquement une séquence, et les valeurs de cette séquence sera utilisé par défaut pour ce champ. Si le champ série n'est pas défini lors de l'insertion d'un nouvel enregistrement, le serveur prend une valeur dans la séquence correspondante. Mais si vous définissez une valeur pour le champ série, le serveur insérera cette valeur. Puisque la séquence ne sait rien de la valeur que vous avez insérée dans le champ série, alors lors de l'insertion d'enregistrements supplémentaires (lors de l'utilisation de la séquence), l'erreur "duplicate key value" peut se produire si le champ série est créé avec une contrainte unique . Vous ne rencontrerez pas ce problème si vous ne définissez pas manuellement les valeurs pour ce champ.

2) UniDAC peut remplir automatiquement un champ à l'aide d'une séquence. Pour cela, vous devez définir les TUniQuery.KeyFields et TUniQuery.SpecificOptions.Values ​​[ ''] keySequence propriétés comme suit:

UniQuery1.KeyFields := 'id'; 
    UniQuery1.SpecificOptions.Values['KeySequence'] := 'test1_id_seq'; 

En outre, en utilisant les TUniQuery.SpecificOptions.Values ​​[ ''] SequenceMode propriété, vous peut spécifier quand exactement UniDAC remplira le champ en utilisant la séquence: lors de l'appel Append/Insert ou Post.

Vous trouverez les informations détaillées sur les propriétés mentionnées ici: http://www.devart.com/unidac/docs/pgsqlprov_article.htm

2

La plupart SQL façon compatible serait de ne pas engager ce domaine dans la requête SQL du tout et laisser laissé NULL puis le remplir sur le serveur via SQL Before Insert trigger de null à une valeur unique.

Cela peut être fait si UniDAC a une personnalisation de requête d'insertion comme TUpdateSQL was.

spécifiant manuellement INSERT requête (ou INSERT-RETURNING si vous devez l'ID plus tard pour des raisons: http://en.wikipedia.org/wiki/SQL_INSERT) est la manière la plus contrôlable, efficace et flexible pour insérer les données.


Cependant, si vous Append et ne veut pas écrire des requêtes SQL pour le faire, alors vous pouvez lire la valeur d'identification du serveur avant de le faire post.

1) déclarer source de contre-ID transactionnel: SQL SEQUENCE

2) requête nextval() avant de le faire après et le mettre dans le champ d'identification (vous pouvez le faire dans le gestionnaire d'événements TDataSet.BeforePost)


Vous pouvez également lire la documentation UniDAC et voir quelques propriétés de séquence apparentée à TUniTable qui automatisent ce processus pour vous. KeySequence et SequenceMode à http://www.devart.com/unidac/docs/pgsqlprov_article.htm#tuniquery_tunitable_tunistoredproc