Subject: Checking Data Before Inserting
Posted By: rit01 Post Date: 2/15/2006 4:45:17 PM
Hi All

I am developing an asp.net2 application and as part of it it will enable members to update their username and password that is stored within a user table within SQL Server.

What I need to make sure is that the username is unique to each record so I was looking for a solution that would check the username field BEFORE performing the insert.

I have been trawling the web to find the best practice to achieve this process and what I have come up with is to check the incoming username value within a stored procedure similar to the one below:


CREATE PROCEDURE dbo.CheckUname 
    @uname VARCHAR(32) 
AS 
BEGIN 
    SET NOCOUNT ON 
 
    IF EXISTS (SELECT 1 FROM Users WHERE uname = @uname) 
        RAISERROR('This value already exists.', 11, 1) 
    ELSE 
        INSERT users (uname) VALUES (@uname) 
END 
GO


My question are if you don't mind..

1. Does this sound like good practice?
2. Could someone guide me in the right direction as to how I would raise this error to the user within my ASP.Net2 page?

Many thanks

Rit
Reply By: jbenson001 Reply Date: 2/16/2006 1:19:54 PM
What I do is to call a stored procedure that looks for the user name, something like this:

declare @cnt int
Select @cnt = (Select count(*) from Users
               Where UserName = @UserName)

I then return the count in an Outupt Paramater.  Then I use that variable on the Page and do the error handling there.

Somthing Like:
If @returnval > 0 Then
   Label1.Text = "UserName already exists"
Else
  ''Do Insert
End If

Jim
 



Reply By: Imar Reply Date: 2/16/2006 3:09:29 PM
In addition to what Jim said, you can also combine the two solutions:
DECLARE @returnValue int
IF EXISTS (SELECT 1 FROM Users WHERE uname = @uname) 
  SET @returnValue = -1
ELSE   
  INSERT users (uname) VALUES (@uname) 
  SET @returnValue = SCOPE_IDENTITY()
END 

RETURN @returnValue
This way, the sproc returns -1 when the user already exists, or its new Id when the insert succeeded.

Personally, I wouldn't raise an error for this, as technically, it's not an error. It's a situation you can check before you do the insert, and you should be able to handle it gracefully, instead of throwing exceptions.

Cheers,

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: jbenson001 Reply Date: 2/16/2006 3:18:54 PM
Imar.. I like that solution... seems much neater...

Reply By: rit01 Reply Date: 2/16/2006 3:27:18 PM
Thanks both for your valuable input... things are starting to sink in now.

Imar, your latest book recommendation has been pre-ordered buddy.

Ta

Rit
Reply By: Imar Reply Date: 2/17/2006 1:46:49 PM
Cool. Thank you....

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: rit01 Reply Date: 2/25/2006 8:31:51 AM
Hi All

What am I doing wrong? Based on the code from Imar I have adapted it to use to check user login info (authentication) too with the return value either being -1 if login details are wrong or their userID (record ID) if login details are correct.

When I use the sproc detailed below in my ASP.Net page the return value I get is 0 (the default RETURN value).. I have checked to make sure that the UserID column within my table is Integer too...



CREATE PROCEDURE GCGetIn

    @username nvarchar(30),
    @password nvarchar(30),

AS

DECLARE @ReturnValue int

IF EXISTS (SELECT [UserID] FROM UserTable INNER 
WHERE Uname = @username AND [Password] = @password)

SET @returnValue = (SELECT [UserID] FROM UserTable 
WHERE Uname = @username AND [Password] = @password)

ELSE

SET @ReturnValue = -1

RETURN @ReturnValue
GO

Reply By: rit01 Reply Date: 2/25/2006 12:49:07 PM
The same with this code too... It just returns a 0 even if the first conditions are met and @returnValue is set to 1... it seems to ignore it.


DECLARE @returnValue int

IF EXISTS (SELECT [user_ID] FROM Users WHERE uname = @uname AND
 [user_ID] <> @user_ID)

SET @returnValue = 1

ELSE

UPDATE [Users] 
SET 
    [Uname] = @Uname, 
    [Password] = @Password

WHERE 
    [User_ID] = @User_ID

SET @returnValue = 0

RETURN @returnValue


... can anyone see what I am doing wrong?

Ta

Rit
Reply By: Imar Reply Date: 2/26/2006 6:53:15 AM
I think this is my bad. I gave you an IF example with a multiple statement code block, without the proper use of BEGIN and END.

In T-SQL, you can use If ELSE END IF without BEGIN and END if you have a single statement, like a SELECT statement or something like SET @someVar = someValue.

However, if you need multiple statements, you need to wrap them in BEGIN and END blocks, similar to VB or the {} signs in languages like JavaScript ot C#.

So, in your code below, SET @returnValue = 0 is always executed as the UPDATE statement is the only statement executed for the Else clause

This should fix it:
DECLARE @returnValue int

IF EXISTS (SELECT [user_ID] FROM Users WHERE uname = @uname AND
 [user_ID] <> @user_ID)
BEGIN
  SET @returnValue = 1
END
ELSE
BEGIN
  UPDATE [Users] 
  SET 
      [Uname] = @Uname, 
      [Password] = @Password
  WHERE 
    [User_ID] = @User_ID

  SET @returnValue = 0
END

RETURN @returnValue
HtH,

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: rit01 Reply Date: 2/26/2006 8:56:16 AM
Thanks Imar that makes the return data behave, But my voyage of Return value discovery now takes a bazaar twist... sorry for the long one!..

I seem to get the return value twice within my ASP.NET page... I have checked over my code both in the page and Sproc but can't see why its doing it... have you ever come accross such a thing? The code is below...


SPROC

...sproc stuff
AS
DECLARE @returnValue int

IF EXISTS (SELECT [user_ID] FROM Users 
WHERE uname = @uname AND [user_ID] <> @user_ID)
BEGIN
SET @returnValue = 1
END
ELSE
BEGIN
UPDATE [Users] 
SET 
    [Uname] = @Uname, 
    [Password] = @Password

WHERE 
    [User_ID] = @User_ID
SET @returnValue = 2
END
RETURN @returnValue


ASP.NET CODE WITHIN UPDATED EVENT


Protected Sub SqlStatus_Updated(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
Handles SqlStatus.Updated
        
Dim ReturnStatus As Integer = _
    Convert.ToInt32(e.Command.Parameters("@returnValue").Value)
        
        SELECT CASE ReturnStatus
                CASE 1
                     Response.Write("Username Already in Use")
                CASE 2
                     Response.Write("Saved!")
        END SELECT
    End Sub


And then I have the following parameter within my UpdateParameters within my SqlDataSource 'SqlStatus':


<asp:Parameter Name="returnValue" 
Type="Int32" 
Direction="ReturnValue" />


Can anyone see why it would want to return the value twice?

Ta

Rit
Reply By: Imar Reply Date: 2/27/2006 3:32:16 AM
What do you mean with "get the return value twice "??

Is the event handler SqlStatus_Updated firing twice?

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: rit01 Reply Date: 2/27/2006 4:00:04 AM
HI Imar

I have found the culprit!.. just now.

'Handles SqlGCIStatus.Updated' When I remove this from the event handler it returns the value once but when added I get it twice.
Reply By: Imar Reply Date: 2/27/2006 4:04:23 AM
That's probably because you have an OnUpdated handler in the markup for the control as well.

In that case, the handler is hooked up twice, and it'll fire twice...

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: rit01 Reply Date: 2/27/2006 4:31:23 AM
Excellent, thanks for your help. One last thing if you don't mind..

Within this SELECT CASE statement I want to bind the result to a Label but for some reason it doesn't like it.. page still loads but the label is not showing any text..


SELECT CASE ReturnStatus
                CASE 1
                     lblalert.Text = "Username Already in Use"
                CASE 2
                     lblalert.Text = "Saved!"
        END SELECT


And I declare my Label like so...

Dim lblalerttext As Label = _
CType(FormView1.FindControl("lblAlertsaved"), Label)



I have checked the value of the 'ReturnStatus' which either show 1 0r 2 (Integer)

Ta

Rit
Reply By: rit01 Reply Date: 2/27/2006 4:33:01 AM
sorry lblalerttext = lblalert... just in my example above is wrong.
Reply By: Imar Reply Date: 2/27/2006 12:47:21 PM
Where did you declare the label? Inside a template for the FormView? In that case,is it possible that the selected template is no longer visible after you performed the update? (That is, the Label is defined in the Update section??)

Can't you just add the Label to the page, outside the FormView and directly change its Text?

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
Reply By: rit01 Reply Date: 2/28/2006 6:57:43 AM
Blimey it must be like helping a monkey... sorry about that... I have set it in the page and it works fine.

No disrespect to monkeys by the way!

Rit
Reply By: Imar Reply Date: 2/28/2006 8:17:02 AM
No offense taken.... ;-)

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.

Go to topic 22063

Return to index page 357
Return to index page 356
Return to index page 355
Return to index page 354
Return to index page 353
Return to index page 352
Return to index page 351
Return to index page 350
Return to index page 349
Return to index page 348