【问题标题】:Transaction Foreign Key Causes: "INSERT statement conflicted with the FOREIGN KEY constraint"事务外键原因:“INSERT 语句与 FOREIGN KEY 约束冲突”
【发布时间】:2012-08-26 19:54:49
【问题描述】:

在执行 SQL Server 事务时如何防止出现以下错误?

我正在尝试将SupplierOrderVehicleRecord 添加到一组两个数据库表中。我正在使用以下内容:

表 SQL 结构:

CREATE TABLE VSI_VehicleRecords
(
    VehicleRecordID INT IDENTITY(1,1) PRIMARY KEY,
    StockNumber INT NOT NULL,
    Status INT NOT NULL,
    Make VARCHAR(50) NOT NULL,
    Model VARCHAR(50) NOT NULL,
    Colour VARCHAR(50) NOT NULL,
    Spefication VARCHAR(255) NOT NULL
)

CREATE TABLE VSI_SupplierOrders
(
    SupplierOrderID INT IDENTITY(1,1) PRIMARY KEY,
    VehicleRecordID INT FOREIGN KEY REFERENCES VSI_VehicleRecords(VehicleRecordID) UNIQUE,
    Timestamp
)

我编写了一个实用方法,它将一组 Sql 查询作为事务运行:

C#执行事务:

    SqlTransaction _Transaction;
    OpenConnection();

    _Transaction = __Connection.BeginTransaction();

    try
    {
        for (int i = 0; i < Commands.Length; i++)
        {
            Commands[i].Connection = __Connection;
            Commands[i].Transaction = _Transaction;
            Commands[i].ExecuteNonQuery();
        }
        _Transaction.Commit();
        return true;
    }
    catch (SqlException e)
    {
        _Transaction.Rollback();
    }

上述函数要执行的SQL命令:

    SqlCommand[] _Commands = new SqlCommand[2];

    string _InsertVehicleQuery = "INSERT INTO VSI_VehicleRecords(StockNumber,Status,Make,Model,Colour,Spefication) VALUES (@StockNumber, @Status, @Make, @Model, @Colour, @Specification);";

    SqlCommand _InsertVehicleCommand = new SqlCommand(_InsertVehicleQuery);
    _InsertVehicleCommand.Parameters.AddWithValue("@StockNumber", __StockNumber);
    _InsertVehicleCommand.Parameters.AddWithValue("@Status", __Status);
    _InsertVehicleCommand.Parameters.AddWithValue("@Make", Make);
    _InsertVehicleCommand.Parameters.AddWithValue("@Model", Model);
    _InsertVehicleCommand.Parameters.AddWithValue("@Colour", Colour);
    _InsertVehicleCommand.Parameters.AddWithValue("@Specification", Specification);

    _Commands[0] = _InsertVehicleCommand;

    string _InsertSupplierOrderQuery = "INSERT INTO VSI_SupplierOrders(VehicleRecordID) VALUES (@VehicleRecordID);";
    SqlCommand _InsertSupplierOrderCommand = new SqlCommand(_InsertSupplierOrderQuery);
    _InsertSupplierOrderCommand.Parameters.AddWithValue("@VehicleRecordID", _VehicleRecordID);

    _Commands[1] = _InsertSupplierOrderCommand;

    DataUtility.NonQueryTransaction(_Commands);   

但是我收到以下错误:

*INSERT 语句与 FOREIGN KEY 约束“FK__VSI_Suppl_Vehic_5165187F”冲突。数据库发生冲突 “jack_test”,表“dbo.VSI_VehicleRecords”,列“VehicleRecordID”。*

【问题讨论】:

  • 您如何确定您在第二个命令中插入的_VehicleRecordID 值?如果是上一个命令中的IDENTITY - 你如何获取/检索它???
  • @marc_s 在运行查询之前,我使用“Select * MAX(...) ..”查询来确定下一个主键。
  • Jack - 在使用 IDENTITY 列时,没有可靠的方法来确定下一个主键。由于系统中的并发活动,或由于可能已失败并回滚的事务,IDENTITY 列的 next始终为 MAX() + 1 ......不要使用那种技术 - 它非常不可靠。相反:让 SQL Server 使用 IDENTITY 列完成它的工作,并获取 SQL Server 已分发的值。只有在INSERT 实际发生之后IDENTITY 列的“下一个”值才真正确定并且可以读取。
  • 查看 podiluska 的回答 - 这是使用IDENTITY 列的唯一可靠方法:(1) 将行插入表中,(2) 获取实际值使用 SCOPE_IDENTITY() 插入 - 没有其他方法可以可靠地工作
  • 为什么要使用多个命令?使用一个命令。循环加载带有参数的命令并执行命令。而 Select Scope_Identity 是如何检索 Iden 的。

标签: c# sql sql-server-2008 tsql


【解决方案1】:

您需要从第一个查询中获取 VehicleRecordID - 您目前没有将 _VehicleRecordID 设置为任何值

为此,您需要在插入 SQL 后附加 ;SELECT Scope_Identity() 并通过 ExecuteScalar 执行命令

但是,创建一个存储过程可能会更容易和更整洁,该存储过程接受两个查询的所有参数并在 SQL Server 上完成工作

例如

create proc CreateRecordAndSupplier
(
     @Stocknumber int,
     ... (etc)
)
as
begin
declare @VR int
      INSERT INTO VSI_VehicleRecords(StockNumber,Status,Make,Model,Colour,Spefication) 
      VALUES (@StockNumber, @Status, @Make, @Model, @Colour, @Specification);

      select @VR = Scope_Identity();

      INSERT INTO VSI_SupplierOrders(VehicleRecordID) VALUES (@VR) 
end

【讨论】:

  • 谢谢,我会调查的。我还没有使用过存储过程,所以我得读一读!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 2020-07-27
  • 2021-05-30
相关资源
最近更新 更多