简体   繁体   English

为什么会发生这种违反UNIQUE KEY约束的情况?

[英]Why does this Violation of UNIQUE KEY constraint happend?

I have been trying to learn some basic SQL and have been working with an imaginary project in order to learn the ropes. 我一直在尝试学习一些基本的SQL,并且一直在与一个虚构的项目合作来学习绳索。

My database has been constructed like this: 我的数据库是这样构造的:

CREATE TABLE [dbo].[People]
(
    [Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
    [SocialSecurityNumber] [nvarchar](13) NOT NULL,
    [FirstName] [nvarchar](50) NOT NULL,
    [LastName] [nvarchar](50) NOT NULL,
    [Email] [varchar](50) NOT NULL
)

CREATE TABLE [dbo].[Employees]
(
    [Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
    [EmployeeCode] [varchar](50) NOT NULL,
    [PersonId] [int] FOREIGN KEY REFERENCES People (Id) NOT NULL
)

CREATE TABLE [dbo].[Administrators]
(
    [Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
    [AdministratorCode] [varchar](50) NOT NULL,
    [EmployeeId] [int] FOREIGN KEY REFERENCES Employees (Id) NOT NULL,
)

I've managed to execute the following query: 我设法执行了以下查询:

INSERT INTO Administrators
VALUES  ('A001', (SELECT Employees.Id FROM Employees
                           INNER JOIN People
                           ON People.Email = @email))

But when I call this procedure: 但是当我调用此过程时:

CREATE PROCEDURE [dbo].[InsertNewAdministrator]
(
    @email VARCHAR(50),
    @administratorCode VARCHAR(50)
)
AS
BEGIN
    SET NOCOUNT ON

    INSERT INTO Administrators
    VALUES (@administratorCode, (SELECT Employees.Id 
                                 FROM Employees
                                 INNER JOIN People ON People.Email = @email))
END

With this code: 使用此代码:

(The p-variable is an instance of the class "administrator" sent to the method. Administrator inherits from person). (p变量是发送给该方法的“ administrator”类的实例。Administrator继承自person。)

using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand(procedureName, conn))
{
    if (procedureName == "InsertNewAdministrator")
    {
       var a = p as Administrator;
       command.Parameters.Add(new SqlParameter("@administratorCode", a.AdministratorCode));                        
    }
    else if (procedureName == "InsertNewEmployee")
    {
       ...
    }
    else
    {
       ...
    }

    command.Parameters.Add(new SqlParameter("@email", p.Email));
    command.CommandType = CommandType.StoredProcedure;

    conn.Open();
    command.ExecuteNonQuery();
}

I get the following error: 我收到以下错误:

Violation of UNIQUE KEY constraint 'UQ__Employee__7AD04F1040881669'." 违反UNIQUE KEY约束'UQ__Employee__7AD04F1040881669'。”

(It's the employeeCode , apparently.) (显然是employeeCode 。)

And I just don't understand why. 我只是不明白为什么。 SQL always adds a new admin, as expected, but the exception makes my business-logic crash. SQL总是按预期方式添加新的管理员,但是异常使我的业务逻辑崩溃。

Right now my code just swallows this in an empty catch... but I still know it's there... lurking... 现在我的代码只是把它吞没了……但是我仍然知道它在那里……潜伏着……

Anyone got any idea why? 有人知道为什么吗?

Administrators has three columns. Administrators有三列。 When you write: 当你写:

INSERT INTO Administrators
    VALUES  ('A001', (SELECT Employees.Id FROM Employees
                               INNER JOIN People
                               ON People.Email=@email))

You are really writing Administrators(ID, AdministratorCode, EmployeeId) . 您实际上是在写Administrators(ID, AdministratorCode, EmployeeId) I have no idea why this works when you run it. 我不知道为什么当您运行它时它会起作用。 You are missing a column. 您缺少一列。

Instead, when you use insert , always list the columns (there is very occasionally an except to this, but definitely not in this simple case). 相反,当您使用insert ,请始终列出各列(偶尔会有一个例外,但在这种简单情况下绝对不是)。 Because the first column is an identity, you do not need to assign it. 因为第一列是一个标识,所以您无需分配它。

Second, your join is missing a join condition between the two tables. 其次,您的join缺少两个表之间的join条件。 In general, you should have at least one equality condition between two tables in an on clause. 通常,在on子句中的两个表之间应该至少有一个相等条件。 This is not required and there are exceptions, but for simple cases like this, remember the rule. 这不是必需的,并且有例外,但是对于像这样的简单情况,请记住规则。

You should also learn insert . . . select 您还应该学习insert . . . select insert . . . select insert . . . select syntax -- it is more powerful than insert . . . values insert . . . select语法-它比insert . . . values功能强大insert . . . values insert . . . values insert . . . values . insert . . . values I'm guessing that you intend: 我猜你打算:

INSERT INTO Administrators(AdministratorCode, EmployeeId)
    SELECT 'A001', e.Id
    FROM Employees e INNER JOIN
         People p
         ON p.id = e.PersonId
    WHERE p.Email = @email;

It seems I've made a logic error when writing my C#. 编写C#时似乎出现了逻辑错误。

if (person is Administrator)
{
 NewPersonProcedureCall("InsertNewAdministrator", person);
}
if (person is Employee)
{
 NewPersonProcedureCall("InsertNewEmployee", person);
}

So my method is called right after an employee has been created. 因此,在创建员工后立即调用我的方法。 Made a quick fix. 快速修复。

if (person is Administrator)
{
 NewPersonProcedureCall("InsertNewAdministrator", person);
}
else if (person is Employee)
{
 NewPersonProcedureCall("InsertNewEmployee", person);
}

So the validation-error is logical since the employee exists. 由于员工存在,因此验证错误是合乎逻辑的。 Sorry people! 抱歉!

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

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