【问题标题】:How to fix "Violation of UNIQUE KEY constraint"如何修复“违反 UNIQUE KEY 约束”
【发布时间】:2020-01-17 12:07:31
【问题描述】:

我正在使用实体框架将用户添加到数据库。 当我将第一个用户添加到数据库时,它可以工作。当我尝试将另一个用户添加到数据库时,我收到错误: System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint

我不太确定我在这里做什么。我什至制作了一个 IF 条件来检查天气密钥是唯一的,但实际的错误消息说我正在插入一个重复的密钥。

这是我当前的代码:

//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);
}

以下是我收到的确切错误消息。

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

我的主键是唯一的;

```
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)
);

```

【问题讨论】:

  • "重复键值为 ()。" - 那里有线索吗?
  • @PaulF 请向下滚动到我的错误代码的底部。我的主键是唯一的

标签: c# sql asp.net .net entity-framework


【解决方案1】:

详细了解 PaulF 的 cmets:

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

这设置了FKUserID,但您还没有为此表设置ID,因此您尝试插入null 值,这就是错误告诉您的内容:The duplicate key value is (&lt;NULL&gt;). 关键这里要注意的是它是UsersInfo_tbl 表,而不是Users_tbl 表。由于您尚未包含 UsersInfo_tbl 表的架构,因此我们不知道主要是什么,或者它是否允许为空。如果确实如此(看起来确实如此),则不应如此。尝试查看这两个表的数据,看看到底发生了什么。

这也表示您的表中已经有一个 null 值,很可能需要使用实际值进行更新。

作为旁注,我发现在表名中添加“tbl”是相当糟糕的。除了外观和感觉不好之外,它还可能导致以后出现问题。其他人也认为这是不好的做法。

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

【讨论】:

  • 您好,感谢您的回复。 context.Users_tbl.Add(user);
  • @Supporttest,说明错误发生在哪里总是一件好事。
【解决方案2】:

错误消息指出“违反 UNIQUE KEY 约束 'UQ__Users_tb__2B5B96C51C3AA70E'。无法在对象 'dbo.Users_tbl' 中插入重复键。重复键值为 ()。” p>

查看消息的下部,我看到 UQ__Users_tb__2B5B96C51C3AA70E 与 TwoFACode 字段相关。

在将用户添加到表的代码中,您没有填充此字段 - 因此违反了具有两个空条目的唯一约束。

"[TwoFACode] NVARCHAR (128) NULL" - 该字段允许为空 - 但由于约束只能有一个空字段。

【讨论】:

  • 我评论后看到了,所以我删除了我的评论。我将IsTwoFAEnabledTwoFACode 混淆了,这可能表明命名是一个错误的选择。
  • 我猜只有在 IsTwoFAEnabled 为真时才需要 TwoFACode 的唯一值——这意味着该字段不能轻易地对其具有唯一约束。
  • 既然您提到它,如果不需要,将TwoFACode 作为UNIQUE 列是没有意义的。
【解决方案3】:

尝试在代码中设置 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).

您在表格中的 UserId 也不应该是 nvarchar 而是 UniqueIdentifer

在 SSMS 中打开您的表格,您可以为您的 guid 设置默认值

或运行命令为您更改。

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

【讨论】:

  • 这是很好的信息,但不幸的是它没有回答这个问题。我不会投反对票,因为您不仅没有足够的 RP 来发表评论,而且评论的时间也太长了。跟上好消息,你会得到更多的RP!
  • 即使 OP 遵循了您的所有想法 - 也会发生同样的异常。
【解决方案4】:

恕我直言,您应该确保“电子邮件”列是唯一的,因为现在您可以获得多个用户(如果数据库中有更多具有相同电子邮件的用户并且您要求第一个,则用户 ID 将是随机的) :

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

确保您使用的是 EntityFramework 库中的 Find() 方法,它将通过 Id 键获取用户(它将首先从上下文中获取数据,而不是访问数据库),而不是使用 Where() linq 方法查询数据库。

如果您的代码是一种方法的范围,那么您不必询问上下文或数据库是否存在用户,而是使用 newGuid 值从“UsersInfo_tbl”设置“FKUserID”属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    相关资源
    最近更新 更多