简体   繁体   English

如何解决“违反UNIQUE KEY约束”

[英]How to fix “Violation of UNIQUE KEY constraint”

I am using Entity Framework to Add a User to the database. 我正在使用实体框架将用户添加到数据库。 When I add the first user to the database, it works. 当我将第一个用户添加到数据库时,它可以工作。 When I try to add another user to the database, I get the error : System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint 当我尝试将另一个用户添加到数据库时,出现错误 :System.Data.SqlClient.SqlException:违反UNIQUE KEY约束

I'm not too sure what I am doing here. 我不太确定我在这里做什么。 I've even made an IF Condition to check weather the key is unique but the actual error messages saying i'm inserting a duplicate key. 我什至已经制定了IF条件来检查天气,钥匙是唯一的,但实际错误消息说我正在插入重复的钥匙。

So here is my current code: 所以这是我当前的代码:

//Create new GUID
string newGuid = Guid.NewGuid().ToString();

//Checking if Primary Key already exists in table
if (!context.Users_tbl.Any(u => u.UserID == newGuid))
{

//Installise New User Class
var user = new Users_tbl()
{
UserID = newGuid,
Email = email,
Password = AESCrypt.Encrypt(password),
};

//Add User to ADO and Commit Changes
context.Users_tbl.Add(user);
context.SaveChanges();

//Find UserID via Email
var userID = context.Users_tbl.Where(p => p.Email == email).Select(p => p.UserID).FirstOrDefault();

//Installise New UserInfo Class
var usersInfo = new UsersInfo_tbl()
{
FKUserID = userID,
FirstName = firstName,
LastName = lastName
};

//Add User to ADO and Commit Changes
context.UsersInfo_tbl.Add(usersInfo);
context.SaveChanges();

//Send Activation Link via Email
SendActivationEmail(userID);

//Set Session ID
Session["UserID"] = userID;
Response.Redirect("/Dashboard/DashBoard.aspx", false);
}

Below is the exact error message I am getting. 以下是我得到的确切错误消息。

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint 'UQ__Users_tb__2B5B96C51C3AA70E'. Cannot insert duplicate key in object 'dbo.Users_tbl'. The duplicate key value is (<NULL>).
The statement has been terminated.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery()
   at System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues)
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   --- End of inner exception stack trace ---
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction)
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()
   at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__35()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.<SaveChangesInternal>b__27()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
   --- End of inner exception stack trace ---
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   at System.Data.Entity.DbContext.SaveChanges()
   at ReapStreamV2.Auth.Signup.SignUp.Submit_Click(Object sender, EventArgs e) in C:\Users\Milan\Documents\ReapStream DEV\ReapStream\ReapStreamV2\Auth\Signup\SignUp.aspx.cs:line 123

My Primary Key is Unique; 我的主键是唯一的;

```
CREATE TABLE [dbo].[Users_tbl] (
    [UserID]            NVARCHAR (128) NOT NULL,
    [Email]             VARCHAR (255)  NOT NULL,
    [Password]          VARCHAR (255)  NOT NULL,
    [IsTwoFAEnabled]    BIT            NOT NULL,
    [TwoFACode]         NVARCHAR (128) NULL,
    [hasActivated]      BIT            NOT NULL,
    [AccessFailedCount] INT            NOT NULL,
    CONSTRAINT [PK__Users_tb__1788CCAC29DEB237] PRIMARY KEY CLUSTERED ([UserID] ASC),
    CONSTRAINT [UQ__Users_tb__2B5B96C51C3AA70E] UNIQUE NONCLUSTERED ([TwoFACode] ASC)
);

```

The error message states "Violation of UNIQUE KEY constraint 'UQ__Users_tb__2B5B96C51C3AA70E'. Cannot insert duplicate key in object 'dbo.Users_tbl'. The duplicate key value is (<NULL>)." 错误消息指出“违反唯一键约束'UQ__Users_tb__2B5B96C51C3AA70E'。无法在对象'dbo.Users_tbl'中插入重复键。重复键值为(<NULL>)。”

Looking at the lower part of your message I see the UQ__Users_tb__2B5B96C51C3AA70E relates to the TwoFACode field. 查看消息的下部,我看到UQ__Users_tb__2B5B96C51C3AA70E与TwoFACode字段相关。

In the code adding the user to the table, you have not populated this field - hence violating the unique constraint with two null entries. 在将用户添加到表的代码中,您尚未填充此字段-因此违反了带有两个空条目的唯一约束。

" [TwoFACode] NVARCHAR (128) NULL " - the field is allowed to be null - but there can only be one null field due to the constraint. [TwoFACode] NVARCHAR(128)NULL ”-允许该字段为null-但由于约束,只能有一个null字段。

To go into more detail of PaulF's comments: 要进一步了解PaulF的评论,请执行以下操作:

var usersInfo = new UsersInfo_tbl()
{
    FKUserID = userID,
    FirstName = firstName,
    LastName = lastName
};

This sets the FKUserID , but you haven't set the ID for this table, so you are trying to insert a null value, which is what the error is telling you: The duplicate key value is (<NULL>). 这将设置FKUserID ,但尚未设置此表的ID ,因此您尝试插入一个null值,这就是错误告诉您的内容: The duplicate key value is (<NULL>). The key to note here is that it's the UsersInfo_tbl table, not the Users_tbl table. 这里要注意的关键是它是UsersInfo_tbl表,而不是Users_tbl表。 Since you haven't included the schema for the UsersInfo_tbl table, we don't know what the primary is for that, or if it allows null. 由于您尚未包含UsersInfo_tbl表的架构,因此我们不知道该表的主要含义是什么,或者它是否允许null。 If it does (which it seems like it does), it shouldn't. 如果确实如此(看起来确实如此),则不应该如此。 Try looking at the data of both tables to see exactly what's going on. 尝试查看两个表的数据以了解发生了什么。

This also says that there's already a null value in your table, which most likely needs to be updated with a real value. 这也表示您的表中已经有一个null值,很可能需要将其更新为实际值。

As a side note, I find adding "tbl" to a table name to be fairly atrocious. 附带说明一下,我发现在表名中添加“ tbl”是相当糟糕的。 Aside from the look & feel of it being bad, it can lead to problems later. 除了外观和感觉很差之外,它还会在以后导致问题。 Other people find it to be bad practice as well. 其他人也认为这是不好的做法。

https://dba.stackexchange.com/questions/154251/is-adding-the-tbl-prefix-to-table-names-really-a-problem https://dba.stackexchange.com/questions/154251/is-adding-the-tbl-prefix-to-table-names-really-a-problem

IMHO You should make sure 'Email' column is unique becouse now you could get more then one user (there is a change userID will be random if there will be more users with same Email in database and you ask for First one): 恕我直言,您应该确保“电子邮件”列是唯一的,因为现在您可以吸引到一个以上的用户(如果数据库中会有更多具有相同电子邮件的用户,并且您要求输入第一个用户,则用户ID的更改将是随机的):

 //Find UserID via Email var userID = context.Users_tbl.Where(p => p.Email == email).Select(p => p.UserID).FirstOrDefault(); 

Make sure you are using Find() method from EntityFramework library with will get user by Id key (it will fetch data from context first instead of making trip to database) instead of query database with Where() linq method. 确保您使用的是EntityFramework库中的Find()方法,并通过ID键获取用户(它将首先从上下文中获取数据,而不是访问数据库),而不是使用Where()linq方法来查询数据库。

If your code is scope of one method than you don't have to ask context or database if user exists but set 'FKUserID' property from 'UsersInfo_tbl' with newGuid value. 如果您的代码属于一种方法的范围,则不必询问上下文或数据库是否存在用户,而是使用newGuid值从“ UsersInfo_tbl”设置“ FKUserID”属性。

Its a bad practice to try setting the guid in code populate the rest of the object (excluding the guid). 尝试在代码中设置guid会填充对象的其余部分(不包括guid),这是一种不好的做法。

var user = new Users_tbl()
{
//UserID = newGuid, You dont need this.
Email = email,
Password = AESCrypt.Encrypt(password),
};

YourRepository.SaveChanges();
var userId = user.UserId; (this should retrieve the guid back).

Also your UserId in the table shouldn't be nvarchar but UniqueIdentifer 此外,表中的UserId不应为nvarchar,而应为UniqueIdentifer

Open your table in SSMS and you could set default value for your guid 在SSMS中打开表格,您可以为guid设置默认值

Or run the command to change it for you. 或运行命令为您更改它。

ALTER TABLE dbo.Users_tbl
   ALTER [UserId] UNIQUEIDENTIFIER DEFAULT NEWID() PRIMARY KEY;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM