如何防止数据库重复

时间:2019-07-14 15:14:06

标签: c# sql .net

我一直在尝试防止重复并输入一条重复的电子邮件或用户名(或两者都输入)时出现错误消息,我想知道我的代码有什么问题。

我已经尝试了一些解决类似问题的方法,但是它们似乎没有用。我不确定我的代码或执行此操作的其他方式是否有问题。它只是运行并执行代码,即使结果重复了,结果也会添加到数据库中。

sqlCon.Open();

string query = "SELECT COUNT(*) FROM SSUser WHERE username=@username AND password=@password AND email=@email";
SqlCommand c1 = new SqlCommand(query);

SqlCommand c = new SqlCommand("insert into SSUser values(@username, @password, @email)", sqlCon);
c.Parameters.AddWithValue("@username", register_username.Text);
c.Parameters.AddWithValue("@password", register_password.Text);
c.Parameters.AddWithValue("@email", register_mail.Text);

SqlCommand check_username = new SqlCommand("SELECT COUNT(*) FROM SSUser WHERE (username=@username) AND (email = @email)", sqlCon);

check_username.Parameters.AddWithValue("@username", register_username.Text);
check_username.Parameters.AddWithValue("@email", register_mail.Text);
int check = (int)check_username.ExecuteScalar();

if (check > 0)
{
    register_error.Visible = true;
}
else
{
    if (register_c.Text != register_password.Text)
    {
        register_error.Visible = true;
    }
    else
    {
        c.ExecuteNonQuery();

        register_username.Text = "";
        register_password.Text = "";
        register_c.Text = "";
        register_mail.Text = "";
        Response.Redirect("Login.aspx");
    }
}

3 个答案:

答案 0 :(得分:0)

为防止重复,请在数据库中创建唯一的约束或索引:

alter table ssuser add constraint unq_ssuser_username unique (username);

alter table ssuser add constraint unq_ssuer_email unique (email);

任何将创建重复项的插入或更新都将返回错误。尝试insertupdate时,您可能想捕获该错误。

答案 1 :(得分:0)

除了戈登·利诺夫(Gordon Linoff)的答案外: 在将唯一性约束添加到数据库中的适当属性之后,您应该可以捕获SqlException:

try {
 c.ExecuteNonQuery();
}
catch (SqlException ex)
{
}

答案 2 :(得分:0)

请考虑为此使用数据库层;这是T-SQL的一个工作示例,正是这样的:

create table [dbo].[SSUser] (
    [UserId] bigint not null identity (0, 1)
  , [UserName] nvarchar(255) not null
  , [Email] nvarchar(255) not null
  , [PasswordHash] varbinary(64) null
  , constraint [dbo_SSUser_Pk] primary key clustered ([UserName] asc) with (data_compression = page)
);
go

create type [dbo].[ISSUser] as table (
    [UserName] nvarchar(255) not null
  , [Email] nvarchar(255) not null
  , [PasswordHash] varbinary(64) null
  , primary key clustered ([UserName] asc)
);
go

create procedure [dbo].[usp_SSUser_Insert] (
    @users [dbo].[ISSUser] readonly
)
as
begin;
    set nocount on;
    set xact_abort on;

    insert into [dbo].[SSUser] (
        [UserName]
      , [Email]
      , [PasswordHash]
    )
    output [inserted].[UserId]
         , [inserted].[Email]
         , [inserted].[PasswordHash]
    select a.[UserName]
         , a.[Email]
         , a.[PasswordHash]
    from @users as a;
end;

以及随附的C#代码将调用该过程并捕获任何错误:

var connectionString = "Data Source=.;Initial Catalog=Koholint;Trusted_Connection=True;";
var userName = register_username.Text;
var email = register_mail.Text;
var passwordHash = register_password.HashBytes;

try {
    var tableMetadata = new[] {
        new SqlMetaData("UserName", SqlDbType.NVarChar, 255),
        new SqlMetaData("Email", SqlDbType.NVarChar, 255),
        new SqlMetaData("PasswordHash", SqlDbType.VarBinary, 64),
    };
    var tableValues = new SqlDataRecord(tableMetadata);

    tableValues.SetValue(0, userName);
    tableValues.SetValue(1, email);
    tableValues.SetValue(2, passwordHash);

    using (var connection = new SqlConnection(connectionString))
    using (var command = connection.CreateCommand()) {
        command.CommandText = "[dbo].[usp_SSUser_Insert]";
        command.CommandTimeout = 15;
        command.CommandType = CommandType.StoredProcedure;

        var tableParameter = new SqlParameter("users", SqlDbType.Structured);

        tableParameter.TypeName = "[dbo].[ISSUser]";
        tableParameter.Value = new[] { tableValues };

        command.Parameters.Add(tableParameter);
        connection.Open();

        using (var reader = command.ExecuteReader()) {
            do {
                while (reader.Read()) {
                    Console.WriteLine(reader.GetInt64(0)); // TODO: something more useful, or maybe nothing...
                }
            } while (reader.NextResult());
        }
    }
}
catch (SqlException e) {
    register_error.Visible = true;

    if (e.Number == 2627) {
        // special handling for primary key/unique constraint violation
    }
    else {
        throw; // rethrow everything else
    }
}

register_username.Text = "";
register_password.Text = "";
register_mail.Text = "";
Response.Redirect("Login.aspx");

为什么要麻烦这些?

第一,它确实防止重复。如果要防止在数据库中重复代码,检查客户端代码中的重复绝对没有任何意义。只需使用primary keyunique constraint阻止它们发生。

另一个主要好处是,我们至少可以保存一次数据库访问。 OP的原始代码必须查询数据库以检查重复项。这不仅在使用相同键值的并发作者面前失败,而且在时间上也很昂贵。

使用table-valued parameter以便将所有输入封装到单个“接口”中,从而可以更轻松地指定C#T-SQL之间的协定。这样做还有一个好处,就是可以让我们在一个事务中插入许多不同的用户,而不用进行某种循环的调用。