none
ADO.NET 4 - Requête d'insertion inclut un SELECT - Possibilité de mise à jour entre le INSERT et le SELECT? RRS feed

  • Question

  • Bonjour,

    J'ai créé une requête pour insérer des données dans une table.  Deux instructions apparaissent automatiquement: INSERT et SELECT.  J'ai modifié ces instructions pour refléter mes besoins.  Les voici:

    INSERT INTO [Récepteur-Queue] ([RécepteurId], [Reçu], [Message]) VALUES (@RécepteurId, @Reçu, @Message);
    SELECT TOP 1 Id, RécepteurId, Reçu, Message, TraitementDébut, TraitementFin FROM [Récepteur-Queue] ORDER BY Id DESC

    Est-ce que je peux exécuter ce genre de requête avec SELECT TOP 1 en étant sûr que je n'aurai pas une autre insertion dans la table? 

    Note: Le champ Id est configuré comme AutoIncrément.


    Luc Saucier



    jeudi 17 mai 2012 14:26

Réponses

  • Il n'y a pas de clause WHERE pour un INSERT en tout cas avec SQL Server (ou on est en MySQL ? ou en tout cas je n'ai jamais vu cela sur SQL Server)

    Cela ne serait pas plutôt un UPDATE ? Dans ce cas c'est normal, il s'agit du "verrouillage optimiste". L'idée est de mettre à jour la ligne si elle n'a pas été modifiée par qq d'autre entre temps ce qui explique la présence des valeurs originales de la ligne dans la clause where.

    Il est possible d'utiliser un "rowversion" à la place (qui est mis à jour automatiquement à chaque mise à jour et est donc le "n° de version" de la ligne).

    Avec SCOPE_IDENTITY pas besoin de se poser la question. La valeur est celle du "scope" actif donc si vous insérer une ligne et passer en attente, insérer d'autres lignes depuis une autre session, lorsque l'attente sera terminée, SCOPE_IDENTITY aura toujours la bonne valeur...

    Sinon cela dépend de la config par défaut et au pire et il serait possible il serait possible de gérer explicitement les transactions si besoin (http://social.msdn.microsoft.com/Forums/da-DK/windowstransactionsprogramming/thread/d9f995a1-1053-46b8-8b9e-c2c898c03f67 )

    A priori par défaut c'est possible (ou de toute façon autant considérer que c'est possible jusqu'à preuve du contraire) car c'est chaque instruction SQL qui est dans une transaction et je ne pense pas que la mise à jour via DataSet mette quoi que ce soit en place pour changer ce principe de base. Donc si on fait INSERT, INSERT dans une autre transaction, SELECT le dernier SELECT ne va pas récupérer la bonne valeur. Franchement pas sûr à 100% (disons 90%) mais je pense qu'il est préférable de prendre la pire option jusqu'à preuve du contraire. Après en pratique, ce serait la faute à pas de bol ;-)

    De mémoire le principe par défaut est que chaque instruction SQL est dans sa transaction sauf si qq demande le contraire (et je pense que les API de base gardent ce principe).

    En conclusion, je suggère fortement de continuer à utiliser SCOPE_IDENTITY qui a le "bon" comportement même en l'absence de transaction (ce qui était peut-être le problème que vous vous posiez au départ ?)


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    mardi 22 mai 2012 15:45
    Modérateur

Toutes les réponses

  • SELECT TOP n'est pas le top ;-)

    Il est préférable d'utiliser SELECT SCOPE_IDENTITY()

    Faites ensuite un ExecuteReader ou un ExecuteScalar() pour récupérer cette valeur.


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    vendredi 18 mai 2012 06:23
  • Bonjour,

    Et les instructions générées automatiquement étaient ? Si on avait un WHERE id=SCOPE_IDENTITY() c'était bien et cela ne semble pas avoir d'intérêt de le remplacer...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    vendredi 18 mai 2012 20:40
    Modérateur
  • Bonjour,

    Je vais préciser ma question originale:

    Est-ce qu'une instruction SQL modifiant la table peut s'insérer entre le INSERT et le SELECT?

    Les instructions originales inclus tous les champs dans le INSERT ... WHERE, ce qui fait pas de sens dans mon cas.  Par la suite, le SELECT ... WHERE Id = @Id est utilisé.

    Par contre, j'ai contourné le problème en récupérant le Id par ADO.NET avec 'NewRow' et passé en paramètre.


    Luc Saucier


    mardi 22 mai 2012 12:39
  • Il n'y a pas de clause WHERE pour un INSERT en tout cas avec SQL Server (ou on est en MySQL ? ou en tout cas je n'ai jamais vu cela sur SQL Server)

    Cela ne serait pas plutôt un UPDATE ? Dans ce cas c'est normal, il s'agit du "verrouillage optimiste". L'idée est de mettre à jour la ligne si elle n'a pas été modifiée par qq d'autre entre temps ce qui explique la présence des valeurs originales de la ligne dans la clause where.

    Il est possible d'utiliser un "rowversion" à la place (qui est mis à jour automatiquement à chaque mise à jour et est donc le "n° de version" de la ligne).

    Avec SCOPE_IDENTITY pas besoin de se poser la question. La valeur est celle du "scope" actif donc si vous insérer une ligne et passer en attente, insérer d'autres lignes depuis une autre session, lorsque l'attente sera terminée, SCOPE_IDENTITY aura toujours la bonne valeur...

    Sinon cela dépend de la config par défaut et au pire et il serait possible il serait possible de gérer explicitement les transactions si besoin (http://social.msdn.microsoft.com/Forums/da-DK/windowstransactionsprogramming/thread/d9f995a1-1053-46b8-8b9e-c2c898c03f67 )

    A priori par défaut c'est possible (ou de toute façon autant considérer que c'est possible jusqu'à preuve du contraire) car c'est chaque instruction SQL qui est dans une transaction et je ne pense pas que la mise à jour via DataSet mette quoi que ce soit en place pour changer ce principe de base. Donc si on fait INSERT, INSERT dans une autre transaction, SELECT le dernier SELECT ne va pas récupérer la bonne valeur. Franchement pas sûr à 100% (disons 90%) mais je pense qu'il est préférable de prendre la pire option jusqu'à preuve du contraire. Après en pratique, ce serait la faute à pas de bol ;-)

    De mémoire le principe par défaut est que chaque instruction SQL est dans sa transaction sauf si qq demande le contraire (et je pense que les API de base gardent ce principe).

    En conclusion, je suggère fortement de continuer à utiliser SCOPE_IDENTITY qui a le "bon" comportement même en l'absence de transaction (ce qui était peut-être le problème que vous vous posiez au départ ?)


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    mardi 22 mai 2012 15:45
    Modérateur
  • Bonjour,

    Pour le INSERT ... WHERE, j'ai tapé trop rapidement.  Je voulais mentionner que tous les champs sont ajoutés par défaut.  Dans le cas concerné, j'ai besoin d'ajouter seulement certains champs.

    La réponse fournie confirme ce que je pensais:  Il est possible qu'entre le INSERT et le SELECT, une transaction se glisse.

    Merci pour toutes ces réponses!


    Luc Saucier

    mardi 22 mai 2012 15:53