111 votes

Comment récupérer le dernier ID auto-incrémenté d'une table SQLite ?

Je possède une table Messages avec les colonnes ID (clé primaire, auto-incrément) et Content (texte).
Je possède une table Utilisateurs avec les colonnes nom d'utilisateur (clé primaire, texte) et Hash.
Un message est envoyé par un Expéditeur (utilisateur) à de nombreux destinataires (utilisateurs) et un destinataire (utilisateur) peut avoir de nombreux messages.
J'ai créé une table Messages_Recipients avec deux colonnes : MessageID (faisant référence à la colonne ID de la table Messages) et Recipient (faisant référence à la colonne nom d'utilisateur dans la table Utilisateurs). Cette table représente la relation de plusieurs à plusieurs entre les destinataires et les messages.

Donc, la question que je me pose est la suivante. L'ID d'un nouveau message sera créé après qu'il a été stocké dans la base de données. Mais comment puis-je conserver une référence à la ligne de Message que je viens d'ajouter afin de récupérer ce nouvel ID de Message?
Je peux toujours chercher dans la base de données la dernière ligne ajoutée bien sûr, mais cela pourrait éventuellement renvoyer une ligne différente dans un environnement multi-threaded?

MODIFIER : Tel que je le comprends pour SQLite, vous pouvez utiliser SELECT last_insert_rowid(). Mais comment puis-je appeler cette instruction depuis ADO.Net?

Mon code de persistence (messages et messagesRecipients sont des DataTables):

public void Persist(Message message)
{
    pm_databaseDataSet.MessagesRow messagerow;
    messagerow = messages.AddMessagesRow(message.Sender,
                            message.TimeSent.ToFileTime(),
                            message.Content,
                            message.TimeCreated.ToFileTime());
    UpdateMessages();
    var x = messagerow;//J'espérais que messagerow retiendrait une
    //référence à la nouvelle ligne dans la table Messages, mais ce n'est pas le cas.
    foreach (var recipient in message.Recipients)
    {
        var row = messagesRecipients.NewMessages_RecipientsRow();
        row.Recipient = recipient;
        //row.MessageID= Comment le trouver ??
        messagesRecipients.AddMessages_RecipientsRow(row);
        UpdateMessagesRecipients();//méthode non affichée
    } 

}

private void UpdateMessages()
{
    messagesAdapter.Update(messages);
    messagesAdapter.Fill(messages);
}

129voto

polyglot Points 3627

Une autre option consiste à consulter la table système sqlite_sequence. Votre base de données sqlite aura automatiquement cette table si vous avez créé une table avec une clé primaire auto-incrémentée. Cette table est utilisée par sqlite pour suivre le champ auto-incrémenté afin qu'il ne répète pas la clé primaire même après la suppression de certaines lignes ou après l'échec de certaines insertions (en savoir plus à ce sujet ici http://www.sqlite.org/autoinc.html).

Ainsi, avec cette table, il y a l'avantage supplémentaire que vous pouvez connaître la clé primaire de votre nouvel élément inséré même après avoir inséré quelque chose d'autre (dans d'autres tables, bien sûr !). Après vous être assuré que votre insertion est réussie (sinon vous obtiendrez un faux numéro), vous avez simplement besoin de faire :

select seq from sqlite_sequence where name="table_name"

114voto

MikeW Points 3392

Avec SQL Server, vous utiliseriez SELECT SCOPE_IDENTITY() pour obtenir la dernière valeur d'identité pour le processus en cours.

Avec SQlite, il semblerait que pour avoir une auto-incrémentation, vous feriez

SELECT last_insert_rowid()

immédiatement après votre insertion.

http://www.mail-archive.com/sqlite-users@sqlite.org/msg09429.html

En réponse à votre commentaire pour obtenir cette valeur, vous voudriez utiliser du code SQL ou OleDb comme suit:

using (SqlConnection conn = new SqlConnection(connString))
{
    string sql = "SELECT last_insert_rowid()";
    SqlCommand cmd = new SqlCommand(sql, conn);
    conn.Open();
    int lastID = (Int32) cmd.ExecuteScalar();
}

15voto

Fidel Points 844

J'ai eu des problèmes avec l'utilisation de SELECT last_insert_rowid() dans un environnement multithread. Si un autre thread insère dans une autre table qui a un auto-incrémentation, last_insert_rowid renverra la valeur auto-incrémentée de la nouvelle table.

Voici où ils indiquent cela dans la documentation :

Si un thread séparé effectue un nouvel INSERT sur la même connexion de base de données pendant que la fonction sqlite3_last_insert_rowid() est en cours d'exécution et modifie ainsi le dernier identifiant d'insertion, alors la valeur retournée par sqlite3_last_insert_rowid() est imprévisible et pourrait ne pas correspondre à l'ancien ou au nouveau dernier identifiant d'insertion.

C'est tiré de la documentation de sqlite.org

9voto

CoolMind Points 11

Selon Android Sqlite obtenir le dernier identifiant de ligne inséré il y a une autre requête :

SELECT rowid from your_table_name order by ROWID DESC limit 1

6voto

Code exemple de la solution @polyglot

SQLiteCommand sql_cmd;
sql_cmd.CommandText = "select seq from sqlite_sequence where name='myTable'; ";
int newId = Convert.ToInt32(sql_cmd.ExecuteScalar());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X