【问题标题】:ADO.NET DataAdapters - Ensuring one Table is Update Before AnotherADO.NET DataAdapters - 确保一个表在另一个表之前更新
【发布时间】:2016-09-10 01:43:32
【问题描述】:

我正在开发一个应用程序,当用户点击提交按钮时,它会将数据插入两个独立但相关的表中。

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_details_report"

但是,由于我在一张表上有外键约束,我一直遇到困难。由于外键限制,我需要先插入一个表(report_summary)的行,然后再将一行添加到另一个表(report_details)。但是,我也希望它们在单个事务中处理,可能存在一个插入成功而另一个失败的一些数据完整性问题。我该如何解决这个问题?

T-SQL

CREATE TABLE [dbo].[report_summary] (
    [report_id]  INT  NOT NULL,
    [inspector]  INT  NOT NULL,
    [employee]   INT  NOT NULL,
    [room]       INT  NOT NULL,
    [date]       DATE NOT NULL,
    [score]      INT  NOT NULL,
    [locationID] INT  NOT NULL,
    PRIMARY KEY CLUSTERED ([report_id] ASC),
    CONSTRAINT [FK_report_summary_locations] FOREIGN KEY ([locationID]) REFERENCES [dbo].[locations] ([locID])
);



CREATE TABLE [dbo].[report_details] (
    [reportID] INT   NOT NULL,
    [itemID]   INT   NOT NULL,
    [points]   INT   NOT NULL,
    [comments] NTEXT NULL,
    PRIMARY KEY CLUSTERED ([itemID] ASC, [reportID] ASC),
    CONSTRAINT [FK_details_items] FOREIGN KEY ([itemID]) REFERENCES [dbo].[items] ([itemID]),
    CONSTRAINT [FK_details_report] FOREIGN KEY ([reportID]) REFERENCES [dbo].[report_summary] ([report_id])
);

还有我的一些 C#

private void submitData(object sender, RoutedEventArgs e)
{
    SqlTransaction tran = con.BeginTransaction();

    reportAdapter.InsertCommand.Transaction = tran;
    SqlCommand query = new SqlCommand("SELECT report_id FROM dbo.report_summary ORDER by report_id DESC", con);
    query.Transaction = tran;
    int nextReportID;
    if (query.ExecuteScalar() != null)
    {
        nextReportID = (int)query.ExecuteScalar() + 1;
    }
    else
    {
        nextReportID = 1;
    }

    detailsAdapter.InsertCommand.Transaction = tran;

    DataRow reportRow = ds.Tables["Reports"].NewRow();
    reportRow["report_id"] = nextReportID;
    DataRowView inspectorSelection = (DataRowView)inspectorBox.SelectedItem;
    reportRow["inspector"] = Int16.Parse(inspectorSelection["empID"].ToString());

    DataRowView empSelection = (DataRowView)employeeBox.SelectedItem;
    reportRow["employee"] = Int16.Parse(inspectorSelection["empID"].ToString());

    DataRowView locationSelection = (DataRowView)locationComboBox.SelectedItem;
    reportRow["locationID"] = Int16.Parse(locationSelection["locID"].ToString());
    reportRow["room"] = Int16.Parse(roomTextBox.Text);
    reportRow["date"] = DateTime.Now.ToString("yyy-MM-dd");
    reportRow["score"] = currentPoints;
    ds.Tables["Reports"].Rows.Add(reportRow);

    // update report_details dataset
    foreach (DataRow row in ds.Tables["Grid"].Rows)
    {
        DataRow reportDetailsRow = ds.Tables["Details"].NewRow();

        reportDetailsRow["reportID"] = nextReportID;
        reportDetailsRow["itemID"] = row["ID"];
        reportDetailsRow["points"] = row["Current"];
        reportDetailsRow["comments"] = row["Comments"];

        ds.Tables["Details"].Rows.Add(reportDetailsRow);

    }

    // update tables as single transaction
    try
    {

        reportAdapter.Update(ds, "Reports");
        detailsAdapter.Update(ds, "Details");
        tran.Commit();
        MessageBox.Show("Data Inserted");
    }
    catch (SqlException sqlEr)
    {
        MessageBox.Show(sqlEr.Message);
        tran.Rollback();
    }
}

我引用了 Microsoft (https://msdn.microsoft.com/en-us/library/33y2221y(v=vs.110).aspx) 的这篇文章,但据我了解,Ordering 部分确实适用于需要更新的一张表。

谢谢!

【问题讨论】:

  • 您是否为数据集中的这两个数据表正确设置了关系?

标签: c# sql ado.net dataset


【解决方案1】:

首先通过插入符合外键构件的要求。保留该值并使用外键关系执行第二个插入。将这些插入包装在交易中。

begin transaction
    INSERT INTO TableA (Id) VALUES (1)
    INSERT INTO TableB (Id, TableAID) VALUES (newid(), 1)
commit transaction

【讨论】:

  • 谢谢,我很欣赏它,但不是我正在寻找的答案。我正在使用ADO.NET数据适配器 - 问题是如何确保第一个适配器完成更新(第一个插入语句已完成,然后在另一个表中执行插入。 span>
  • 同步运行代码 - 没有委托或回调。 span>
猜你喜欢
  • 1970-01-01
  • 2013-02-15
  • 2016-09-08
  • 2018-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多