none
utiliser le scope_identity c# et utiliser l'id pour nommer un fichier RRS feed

  • Question

  • Bonjour a tous (je suis en qwerty et pas d'accents ;0)),

    J'utilise un FileUpload pour permettre d'uploader un fichier.

    Je souhaiterai lors de l'enregistrement du fichier qu'il soit nomme avec l'ID recupere du scope_identity.

    Comme je suis nul, je parviens juste a afficher dans un label la valeur pour voir si cela fonctionne.

    Donc, Je parviens a recuperer un scope_identity par l'intermediaire d'une sp que voici

    ALTER PROCEDURE dbo.FileUpload
    	
    	(
    	@Filename nvarchar(250),
    	@FilePath nvarchar(250),
    	@IDPersonne BigInt,
    	@FileId int OUTPUT
    	)
    AS
    	SET NOCOUNT ON
    
    	INSERT INTO FilesUpload
    	                         (FileName,FilePath,IDPersonne)
    							 
    			VALUES        (@FileName,@FilePath,@IDPersonne)
    	
    	SELECT @FileId = SCOPE_IDENTITY()
    
    	RETURN @FileId

    Ensuite, voici une partie du fichier en c#

    protected void btnUpload_Click(object sender, EventArgs e)
    {
        
        SqlCommand cmd = new SqlCommand("FileUpload", con);
        cmd.CommandType = CommandType.StoredProcedure;
    
        cmd.Parameters.Add("@FileId", SqlDbType.BigInt);
        cmd.Parameters["@FileId"].Direction = ParameterDirection.Output;
      
        cmd.Connection.Open();
         
        string filename = Path.GetFileName(fileUpload1.PostedFile.FileName);
        if (System.IO.File.Exists(Server.MapPath("Files/" + Request.QueryString["IDP"] + "_" + filename)))
        {
            Label1.Text = "File Name already exists!";
            return;
        }
        else
        {
            fileUpload1.SaveAs(Server.MapPath("Files/" + Request.QueryString["IDP"] + "_" + filename));
        }
    
        cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + "_" + filename);
        cmd.Parameters.AddWithValue("@FilePath", "Files/" + Request.QueryString["IDP"] + "_" + filename);
        cmd.Parameters.AddWithValue("@IDPersonne", Request.QueryString["IDP"]);
        
        cmd.ExecuteScalar();
        string p = cmd.Parameters["@FileId"].Value.ToString();
        Label2.Text = "Record inserted successfully. ID = " + p;
        
        con.Close();
        BindGridviewData();
    }

    Comment faire pour dire que 

    cmd.Parameters["@FileId"]

    puisse etre affiche lors de l'insert la

    cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + "_" + filename);

    Je capitule !

    Merci d'avance.

    mercredi 4 avril 2012 16:47

Réponses

  • Donc la solution 2 serait d'utiliser dans la procédure la valeur qui vient d'être générée dans le "INSERT" ce qui donnerait qq chose comme :

    INSERT INTO FilesUpload(FileName,FilePath,IDPersonne) VALUES (@FileName,@FilePath+'NotFound.htm',@IDPersonne) SELECT @FileId = SCOPE_IDENTITY() UPDATE FilesUpload SET FilePath=@FilePath+"_"+CAST(@FileId AS VARCHAR)+@FileName WHERE FileId=@FileId
    RETURN @FileId

    Je suppose aussi que @FilePath ne contient plus le @FileName qui est de toute façon passé séparemment ce qui facilite dans la procédure l'assemblage des différentes parties du chemin.


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

    jeudi 5 avril 2012 09:55
    Modérateur
  • Directement dans le INSERT on pourrait éventuellement utiliser IDENT_CURRENT pour récupérer la valeur en cours. :

    create table tmp(id int identity,data int)
    go
    insert into tmp(data) values (ident_current('tmp'))
    insert into tmp(data) values (ident_current('tmp'))
    select * from tmp
    go
    drop table tmp

    Montre que l'on a bien dans la colonne Data, la même chose que ce qu'on a généré dans la colonne id.

    Sinon c'est exactement comme une fonction C# :

    - si vous appelez une fonction C# et que vous voulez faire qq chose avec son résultat, vous ne pourrez pas passer en paramètre de cette fonction la valeur que cette fonction VA générer.

    Vous aurez deux solutions : soit inclure dans cette fonction, les opérations supplémentaires que vous voulez faire avec la valeur générée au début de cette fonction. Soit appeler cette fonction pour récupérer la valeur générée et appeler une deuxième fonction avec comme entrée la valeur retournée par la première fonction pour en faire autre chose...

    Le cas #1 correspond à l 'utilisation de SCOPE_IDENTITY ou IDENT_CURRENT directement dans la procédure stockée. Le cas #2 correspondrait à faire un premier cmd.ExecuteNonQuery pour faire l'insertion et récupérer le nouvel id pour faire un deuxième cmd.ExecuteQuery avec le FileId en paramètre pour mettre à jour correctement le FilePath...


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

    vendredi 6 avril 2012 11:21
    Modérateur

Toutes les réponses

  • Bonjour,

    Pas sûr de comprendre ce que veut dire "afficher" un paramètre dans un autre paramètre ?

    Je crois comprendre que vous voudriez utiliser la valeur de *sortie* de la procédure stockée pour calculer un de ses argument *d'entrée* ce qui n'est bien sûr pas possible.

    Je vois deux solutions :

    - faire 2 appels (un premier qui insère la ligne, un deuxième qui modifie le nom)
    - incorporer la modification du nom dans la procédure déjà existante (en faisant un UPDATE après avoir récupéré le n° de la nouvelle ligne)
    - ou même une 3 ème qui serait d'utiliser un guid (http://msdn.microsoft.com/fr-fr/library/system.guid.aspx), l'avantage étant dans ce cas que c'est le code C# qui peut générer cette nouvelle valeur et la communiquer à la procédure

    Sinon expliciter un peu mieux le genre de "lien" que vous voulez faire entre ces deux paramètres.
     


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

    mercredi 4 avril 2012 17:42
    Modérateur
  • Bonsoir,

    En fait, lorsque l'utilisateur upload un fichier, ce dernier est sauvegarder dans le dossier Files/.

    Si le fichier de depart est "CVRicardo.doc", pour l'instant il est sauvegarde comme suit : "4307_CVRicardo.doc"

    "4307" est un ID recupere par un querystring

     fileUpload1.SaveAs(Server.MapPath("Files/" + Request.QueryString["IDP"] + "_" + filename));

    et le nom de ce fichier se retrouve dans un gridview "gv_details" grace a

    cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + "_" + filename);

    Je souhaiterai utiliser l'id du scope_identity lors de l'insertion dans la tabe dbo.FileUpload

    pour nommer le fichier avec ce scope : 4307_1_CVRicardo.doc ou "1" serait le premier id retourne par le scope ensuite 2 puis 3 etc...

    Pour verifier si le scope retourne bien la valeur je l'ai juste affichee dans un label histoire de voir si ca fonctionne. 

     string p = cmd.Parameters["@FileId"].Value.ToString();
        Label2.Text = "Record inserted successfully. ID = " + p;

    mais cela ne me sert pas bien sur.

    Un tout grand merci deja pour vous etre penche sur la question.

    mercredi 4 avril 2012 18:10
  • Bonjour,

    Voici une version modifiée de votre méthode :

           protected void btnUpload_Click(object sender, EventArgs e)
            {
    
                SqlCommand cmd = new SqlCommand("FileUpload", con);
                cmd.CommandType = CommandType.StoredProcedure;
    
                cmd.Parameters.Add("@FileId", SqlDbType.BigInt);
                cmd.Parameters["@FileId"].Direction = ParameterDirection.Output;
    
                cmd.Connection.Open();
    
                cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + "_" + filename);
                cmd.Parameters.AddWithValue("@FilePath", "Files/" + Request.QueryString["IDP"] + "_" + filename);
                cmd.Parameters.AddWithValue("@IDPersonne", Request.QueryString["IDP"]);
    
                cmd.ExecuteScalar();
                string p = cmd.Parameters["@FileId"].Value.ToString();
                
    
                //Sauvegarde du fichier avec 
                string filename = Path.GetFileName(fileUpload1.PostedFile.FileName);
                fileUpload1.SaveAs(Server.MapPath("Files/" + Request.QueryString["IDP"] + "_" + p + "_" + filename));
    
                con.Close();
                BindGridviewData();
            }


    Après tous je ne suis pas sûr de bien comprendre le problème.

    Cordialement.

    jeudi 5 avril 2012 09:09
    Auteur de réponse
  • Donc la solution 2 serait d'utiliser dans la procédure la valeur qui vient d'être générée dans le "INSERT" ce qui donnerait qq chose comme :

    INSERT INTO FilesUpload(FileName,FilePath,IDPersonne) VALUES (@FileName,@FilePath+'NotFound.htm',@IDPersonne) SELECT @FileId = SCOPE_IDENTITY() UPDATE FilesUpload SET FilePath=@FilePath+"_"+CAST(@FileId AS VARCHAR)+@FileName WHERE FileId=@FileId
    RETURN @FileId

    Je suppose aussi que @FilePath ne contient plus le @FileName qui est de toute façon passé séparemment ce qui facilite dans la procédure l'assemblage des différentes parties du chemin.


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

    jeudi 5 avril 2012 09:55
    Modérateur
  • Merci beaucoup,

    Le probleme dans votre proposition est que la variable filename doit etre declaree avant

      cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + "_" + filename);
                cmd.Parameters.AddWithValue("@FilePath", "Files/" + Request.QueryString["IDP"] + "_" + filename);
                cmd.Parameters.AddWithValue("@IDPersonne", Request.QueryString["IDP"]);


    car il faudrait que lors de l'insert dans le gridview l'ID genere par le scope s'insere dans le nom du fichier.

    Et si vous placer comme ceci

    protected void btnUpload_Click(object sender, EventArgs e)
    {
        
        SqlCommand cmd = new SqlCommand("FileUpload", con);
        cmd.CommandType = CommandType.StoredProcedure;
    
        cmd.Parameters.Add("@FileId", SqlDbType.BigInt);
        cmd.Parameters["@FileId"].Direction = ParameterDirection.Output;
        
        cmd.Connection.Open();
         
        string filename = Path.GetFileName(fileUpload1.PostedFile.FileName);
        string p = cmd.Parameters["@FileId"].Value.ToString();
        if (System.IO.File.Exists(Server.MapPath("Files/" + Request.QueryString["IDP"] + p + "_" + filename)))
        {
            Label1.Text = "File Name already exists!";
            return;
        }
        else
        {
            fileUpload1.SaveAs(Server.MapPath("Files/" + Request.QueryString["IDP"] + p + "_" + filename));
        }
    
        cmd.Parameters.AddWithValue("@FileName", Request.QueryString["IDP"] + p + "_" + filename);
        cmd.Parameters.AddWithValue("@FilePath", "Files/" + Request.QueryString["IDP"] + p + "_" + filename);
        cmd.Parameters.AddWithValue("@IDPersonne", Request.QueryString["IDP"]);
        
        cmd.ExecuteScalar();
          
        
        con.Close();
        BindGridviewData();
    }

    J'ai une erreur de type La référence d'objet n'est pas définie à une instance d'un objet. Merci en tous les cas

    jeudi 5 avril 2012 10:01
  • Merci Patrice,

    Je vais essayer.

    Et est ce que je pourrais faire un cast du scope_identity : CAST(SCOPE_IDENTITY() AS VARCHAR) ?

    jeudi 5 avril 2012 10:21
  • Oui, cela ne devrait faire aucune différence. Choisir ce qui semble le plus clair.

    Il pourrait être intéressant de mettre un paramètre de retour pour récupérer le chemin complet généré par la procédure à partir des paramètres et du nouvel id, afin de réutiliser ce chemin dans la sauvegarde du fichier.


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

    jeudi 5 avril 2012 10:55
    Modérateur
  • Je ne parviens pas a recuperer @FileId...

    Je comprends pas.

    sauf apres

    cmd.ExecuteScalar();    

        string p = cmd.Parameters["@FileId"].Value.ToString();

    jeudi 5 avril 2012 18:51
  • "Sauf après" ? C'est normal. On dirait que vous voulez récupérer @FileId AVANT que la procédure ne soit exécutée alors que c'est cette procédure stockée qui le génère ?

    Le principe est :
    - cmd.ExecuteScalar lance l'exécution de la procédure stockée sur le serveur base de données
    - cette procédure génère le nouvel id
    - dès qu'il est généré elle peut ensuite le réutiliser dans les instructions suivantes de cette procédure stockée (pour mettre à jour le FilePath par exemple)
    - lorsqu'elle se termine elle peut renvoyer des résultats
    - que l'on peut alors exploiter juste après la ligne cmd.ExecuteScalar ce qui est tout à fait normal

    Accessoirement ExecuteScalar est prévu pour retourner en valeur de retour la première colonne de la première ligne. Si vous ne renvoyez pas de données via ce moyen cmd.ExecuteNonQuery est suffisant (mais c'est un détail).

    Pour l'instant j'ai l'impression que vous vous attendez à un autre comportement que le comportement qui me semble normal ?

    Ou alors vous voulez dire que vous n'arrivez pas à réutiliser @FileId dans la procédure stockée ?


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



    vendredi 6 avril 2012 07:58
    Modérateur
  • Merci beaucoup. Vous avez raison...

    Je crois que me suis perdu en chemin.

    Je pensais qu'au moment de l'insert je serai parvenu a utiliser l'ID pour nommer le fichier FileName.

    Donc le chemin correct c'est celui de l'update que vous propose ?

    J'ai cru voir que l'instruction OUTPUT inserted.FileId pourrait aussi etre une piste ?

    D'autre part, je ne sais pas comment reutiliser @FileId dans ce contexte... je decouvre c#.

    (je prends qq vacances, en esperant que la question soit encore disponible a mon retour)

    En attendant, je vous remercie encore pour vous etre penche sur ma question et pour ces eclaircissements.

    Ricardo.

    vendredi 6 avril 2012 10:26
  • Directement dans le INSERT on pourrait éventuellement utiliser IDENT_CURRENT pour récupérer la valeur en cours. :

    create table tmp(id int identity,data int)
    go
    insert into tmp(data) values (ident_current('tmp'))
    insert into tmp(data) values (ident_current('tmp'))
    select * from tmp
    go
    drop table tmp

    Montre que l'on a bien dans la colonne Data, la même chose que ce qu'on a généré dans la colonne id.

    Sinon c'est exactement comme une fonction C# :

    - si vous appelez une fonction C# et que vous voulez faire qq chose avec son résultat, vous ne pourrez pas passer en paramètre de cette fonction la valeur que cette fonction VA générer.

    Vous aurez deux solutions : soit inclure dans cette fonction, les opérations supplémentaires que vous voulez faire avec la valeur générée au début de cette fonction. Soit appeler cette fonction pour récupérer la valeur générée et appeler une deuxième fonction avec comme entrée la valeur retournée par la première fonction pour en faire autre chose...

    Le cas #1 correspond à l 'utilisation de SCOPE_IDENTITY ou IDENT_CURRENT directement dans la procédure stockée. Le cas #2 correspondrait à faire un premier cmd.ExecuteNonQuery pour faire l'insertion et récupérer le nouvel id pour faire un deuxième cmd.ExecuteQuery avec le FileId en paramètre pour mettre à jour correctement le FilePath...


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

    vendredi 6 avril 2012 11:21
    Modérateur
  • Ok je teste ca des que je rentre et je vous tiens au courant ss fautes.

    Un tt gd merci encore.

    Bon we.

    vendredi 6 avril 2012 12:23
  • Bonjour,

    Puis que vous parlez de test, avez vous testé la solution que je vous ai proposé ici  http://social.msdn.microsoft.com/Forums/fr-FR/visualcsharpfr/thread/148d0b9d-f266-4565-94bb-5f69179be1c7/#004c744c-75d1-460e-b09b-063e279b5aff ?

    Si vous voulez la tester copier le code de la méthode dans son intégralité.

    Cordialement.

    vendredi 6 avril 2012 14:29
    Auteur de réponse