0

我正在尝试对注册表单进行验证,以检查用户名/姓名+姓氏是否已经存在。

这是我尝试过的:

Dim conn As New SqlConnection("Data Source=BRIAN-PC\SQLEXPRESS;Initial Catalog=master_db;Integrated Security=True")
    Dim registerSQL As SqlCommand
    Dim checkCredentialsSQL As SqlCommand
    Dim sqlComm As String
    Dim sqlCommName As String
    Dim sqlCommUsername As String

    sqlComm = "INSERT INTO users(Username, Password, Name, Surname, Address1, Address2, " +
        "City, Country, date_of_birth, age, Occupation, department, work_location, " +
        "project_manager,team_leader, team_leader_id, project_manager_id, " +
        "date_registration, contract_type, contract_duration) " +
        "VALUES(@p1, @p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,@p11,@p12,@p13,@p14,@p15," +
        "@p16,@p17,@p18,@p19,@p20)"

    sqlCommName = "SELECT name, surname FROM users WHERE name='" + txtName.Text + "' and surname='" + txtSurname.Text + "'"
    sqlCommUsername = "SELECT username FROM users WHERE username='" + txtUsername.Text + "'"

    conn.Open()

    checkCredentialsSQL = New SqlCommand(sqlCommName, conn)


    If checkCredentialsSQL.ExecuteScalar IsNot Nothing Then

        lblName.Text = txtName.Text + " " + txtSurname.Text + "is already registered."
        lblName.Visible = True


    Else

        checkCredentialsSQL = New SqlCommand(sqlCommUsername, conn)

        If checkCredentialsSQL.ExecuteScalar IsNot Nothing Then

            lblUsername.Text = "'" + txtUsername.Text + "' is already taken."

        Else


            registerSQL = New SqlCommand(sqlComm, conn)
            registerSQL.Parameters.AddWithValue("@p1", Username)
            registerSQL.Parameters.AddWithValue("@p2", Password)
            registerSQL.Parameters.AddWithValue("@p3", Name)
            registerSQL.Parameters.AddWithValue("@p4", Surname)
            registerSQL.Parameters.AddWithValue("@p5", Address1)
            registerSQL.Parameters.AddWithValue("@p6", Address2)
            registerSQL.Parameters.AddWithValue("@p7", City)
            registerSQL.Parameters.AddWithValue("@p8", Country)
            registerSQL.Parameters.AddWithValue("@p9", DOB)
            registerSQL.Parameters.AddWithValue("@p10", Age)
            registerSQL.Parameters.AddWithValue("@p11", Occupation)
            registerSQL.Parameters.AddWithValue("@p12", Department)
            registerSQL.Parameters.AddWithValue("@p13", WorkLocation)
            registerSQL.Parameters.AddWithValue("@p14", ProjectManager)
            registerSQL.Parameters.AddWithValue("@p15", TeamLeader)
            registerSQL.Parameters.AddWithValue("@p16", TeamLeaderID)
            registerSQL.Parameters.AddWithValue("@p17", ProjectManagerID)
            registerSQL.Parameters.AddWithValue("@p18", RegistrationDate)
            registerSQL.Parameters.AddWithValue("@p19", ContractType)
            registerSQL.Parameters.AddWithValue("@p20", ContractDuration)

            registerSQL.ExecuteNonQuery()



        End If

    End If

    conn.Close()

这样做是否可行/安全/建议这样做?

4

3 回答 3

1

这是一个简单的存储过程,它检查您要检查的两个条件(更多内容见下文):

CREATE PROCEDURE dbo.CreateUser
  @username NVARCHAR(255),
  @name     NVARCHAR(64),
  @surname  NVARCHAR(64)
  /* ... other params ... */
AS
BEGIN
  SET NOCOUNT ON;

  IF EXISTS (SELECT 1 FROM dbo.users WHERE username = @username) 
  BEGIN
    RAISERROR('Username %s is already registered.', 11, 1, @username);
    RETURN -1;
  END

  IF EXISTS (SELECT 1 FROM dbo.users WHERE name = @name AND surname = @surname) 
  BEGIN
    RAISERROR('Name %s %s is already registered.', 11, 1, @name, @surname);
    RETURN -2;
  END

  BEGIN TRY
    INSERT dbo.Users(username,  name,  surname,  ...other columns...)
             SELECT @username, @name, @suername, ...other params...;
  END TRY
  BEGIN CATCH
    DECLARE @msg NVARCHAR(255) = ERROR_MESSAGE();
    RAISERROR(@msg, 11, 1);
    RETURN -3;
  END CATCH
END

现在您的 VB.Net 代码要简单得多:

Dim conn As New SqlConnection("...conn string...")
conn.Open()
Dim sql As New SqlCommand("dbo.CreateUser", conn)
sql.CommandType = CommandType.StoredProcedure
rv = sql.Parameters.Add("@rv", SqlDbType.Int)
rv.Direction = ParameterDirection.ReturnValue    

sql.Parameters.AddWithValue("@username", Username)
sql.Parameters.AddWithValue("@name",     Name)
sql.Parameters.AddWithValue("@surname",  Surname)
... other params ...

sql.ExecuteNonQuery()
Debug.Print "Return value: " & rv.ToString

...act accordingly depending on error raised and/or return value     
...maybe you want TRY/CATCH here?

conn.Close()

虽然尝试插入(使用WHERE子句,或者只是让约束引发错误)在技术上可能是一种可行的方法,但我认为这不是一个好主意。第一个是因为您的代码无法告诉您是哪个条件导致了问题,第二个是因为让 SQL Server 为您引发异常非常昂贵:

当然,这并不意味着你不应该有潜在的限制。它们应该存在于用户不通过您的存储过程、应用程序层等的情况下。

哦,我同意其他人的观点。你真的认为只有一个约翰史密斯会注册吗?与其他人同名并不是阻止某人注册恕我直言的非常正当的理由。


PS 如果我的 VB.Net 代码远非完美,我深表歉意。我不是用VB写的,其中一些是有根据的猜测......

于 2013-03-30T19:17:30.877 回答
0

虽然我不同意您使用的标准(因为姓名+姓氏几乎肯定不是一个人的唯一标识符),但一般形式应该是一种尝试INSERT

INSERT INTO TabA (Val1,Val2,Val3)
SELECT @Val1,@Val2,@Val3
WHERE NOT EXISTS (SELECT * FROM TabA where Val1 = @Val1 or (Val2 = @Val2 and Val3 = @Val3)

否则,您仍然将自己暴露在竞争条件下。

而且,根据您正在运行的并发设置,您可能需要处理违反约束(我假设您正在执行您在数据库级别也有的任何唯一性约束)

于 2013-03-30T18:51:59.180 回答
0

sqlCommName命令不受 SQL 注入的保护。如果txtName.Text包含existing_username AND 1 = 0用户可以注册两次。

于 2013-03-30T18:05:03.753 回答