J'ai le SP suivant:
ALTER Procedure [dbo].[SP_RegisterComp] @CompName varchar(100) ,@Check_In datetime ,@ID int output As Set NoCount On Update Host Set [Check_In]=@Check_In Where [CompName]=@CompName If @@RowCount=0 Insert into Host values (@CompName, @Check_In) SET @ID=SCOPE_IDENTITY() RETURN @ID
Cela fonctionne bien. Si un nom d'ordinateur existe déjà dans la table, l'heure d'arrivée est mise à jour, sinon elle crée un nouvel logging et renvoie l'ID.
Comment puis-je get le @id lorsque l'logging est mis à jour?
À votre santé,
John
Vérifiez simplement si la ligne existe déjà au lieu de laisser @@ROWCOUNT
vous dire si l'insertion est nécessaire.
ALTER PROCEDURE [dbo].[SP_RegisterComp] @CompName varchar(100) ,@Check_In datetime ,@ID int output AS SET NOCOUNT ON; SELECT TOP 1 @Id = [IdField] FROM Host WHERE [CompName] = @CompName ORDER BY [Check_In] DESC IF (@Id IS NOT NULL) BEGIN UPDATE Host SET [Check_In]=@Check_In WHERE [IdField] = @Id END ELSE BEGIN INSERT INTO Host VALUES (@CompName, @Check_In) SET @ID=SCOPE_IDENTITY() END RETURN @ID
Vous devez configurer un paramètre de Output
. Le code pourrait ressembler à ceci:
using (SqlConnection c = new SqlConnection(cSsortingng)) using (SqlCommand cmd = new SqlCommand("SP_RegisterComp", c)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@CompName", compName); cmd.Parameters.AddWithValue("@Check_In", checkIn); var outParm = new SqlParameter("@ID", SqlDbType.Int); outParm.Direction = ParameterDirection.Output; cmd.ExecuteNonQuery(); var val = outParm.Value; }
Comme Aaron l'a suggéré, c'est un très bon candidat pour le locking, et la programmation transactionnelle est toujours une bonne pratique ici aussi. Ainsi, le code modifié pourrait ressembler à ceci:
lock (_lockObj) { using (SqlConnection c = new SqlConnection(cSsortingng)) using (SqlTransaction tran = c.BeginTransaction()) using (SqlCommand cmd = new SqlCommand("SP_RegisterComp", c, tran)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@CompName", compName); cmd.Parameters.AddWithValue("@Check_In", checkIn); var outParm = new SqlParameter("@ID", SqlDbType.Int); outParm.Direction = ParameterDirection.Output; cmd.ExecuteNonQuery(); // commit the transaction tran.Commit(); var val = outParm.Value; } }
où _lockObj
est défini comme private object _lockObj = new Object();
comme un champ.
Remarque: vous n'avez pas besoin de vous inquiéter de la Rollback
ici car si une exception est SqlTransaction
la SqlTransaction
sera lancée pendant l' SqlTransaction
object SqlTransaction
.
Vous devriez vérifier si l'logging existe:
If EXISTS (SELECT * FROM Host WHERE [CompName] = @CompName) BEGIN BEGIN TRAN SELECT @ID=ID FROM Host WITH(UPDLOCK) WHERE Comp_Name = @Comp_Name UPDATE Host SET [Check_In] = @Check_In WHERE [Comp_Name] = @Comp_Name RETURN @ID COMMIT TRAN END ELSE BEGIN Insert into Host values (@CompName, @Check_In) SET @ID=SCOPE_IDENTITY() RETURN @ID END
Puisque vous devez l'avoir envoyé, il est déjà dans la @Id
t-sql, qui est une variable de sortie donc il est accessible dans le code client ado.net
J'aime le motif suivant
Alter Procedure [dbo].[SP_RegisterComp] @CompName varchar(100), @Check_In datetime. @ID int = null As Set NoCount On If @Id is null Begin Insert ... SET @ID=SCOPE_IDENTITY() End Else Begin Update ... Where id = @Id End Select @Id id Return 0
Ensuite, dans le code client, vous obtiendrez un jeu de résultats à une seule ligne et une seule colonne (une table ADO.Net) avec la valeur de l'ID dans tous les cas.