【问题标题】:Problem with Database - Foreign Key always Null (T-SQL)数据库问题 - 外键始终为空 (T-SQL)
【发布时间】:2019-07-06 04:39:21
【问题描述】:

我的问题描述起来可能有点长,因为我们正在进行的项目有点大,但我会尽量做到准确。

基本上,我们正在开发一个基于网络的伤口管理(大学项目的一部分),用户可以在其中输入伤口并设置其他信息,如大小、一致性、上传图片、选择位置等。 所有这些信息都应存储在数据库中(我们正在使用 MS SQL Studio 和 Visual Studio 2017),用户也可以稍后检索它以在模块上查看。

我们现在面临的问题是,如果我们想向用户显示一个特殊伤口的伤口,我们无法让外键工作。 我们可以通过 casenumber 进行过滤(这是有效的),但我们不能通过伤口的 ID 过滤伤口信息(每个伤口都有一个唯一的 ID) - 所以如果我们选择一个伤口,我们仍然会得到关于所有伤口的信息为给定的 casenr 存储。

这是我们的“主表”,每个伤口都有一个唯一的 ID,这也是一个升序的标识列:

    [wound_id]          INT           IDENTITY (1, 1) NOT NULL,
    [wound_type]        VARCHAR (500) NULL,
    [wound_description] VARCHAR (500) NULL,
    [decuGrade]         INT           NULL,
    [wound_comments]    VARCHAR (500) NULL,
    [wound_timeReal]    DATETIME      NULL,
    [wound_timeGiven]   DATETIME      NULL,
    [casenumber]        INT           NULL,
    [username]          VARCHAR (50)  NULL,
    PRIMARY KEY CLUSTERED ([wound_id] ASC)
);

如果用户输入信息并单击“下一步”,则会在代码中调用一个函数来填充表格:

 _db.SaveWoundDetails(casenr, woundValue, decu, additional_info, realTime, givenBackDocDate, user);

这导致了我们的数据库类,我们在该类中查询数据库,在这种情况下:

 public void SaveWoundDetails(int casenr, string woundType, int decuGrade, string woundComment, DateTime timeReal, DateTime timeGiven , string user)
        {
            var table = ConfigurationManager.AppSettings["woundDetailsTable"];
            var insertQuery = "INSERT INTO " + table + "(casenumber, wound_type, decuGrade, wound_comments, wound_timeReal, wound_timeGiven, username) VALUES (@casenr, @woundType, @decuGrade, @woundComment, @timeReal, @timeGiven, @user)";


            var cmd = new SqlCommand(insertQuery);

            cmd.Parameters.AddWithValue("@casenr", casenr);
            cmd.Parameters.AddWithValue("@woundType", woundType);
            cmd.Parameters.AddWithValue("@decuGrade", decuGrade);
            cmd.Parameters.AddWithValue("@woundComment", woundComment);
            cmd.Parameters.AddWithValue("@timeReal", timeReal);
            cmd.Parameters.AddWithValue("@timeGiven", timeGiven);
            cmd.Parameters.AddWithValue("@user", user);
            var db = DatabaseController.getDataBaseController();

            try
            {
                var sqlcmd = db.executeSQL(cmd);
            }
            catch (SqlException e)
            {

            }
        }

连接等位于数据库处理程序类中,目前不相关。

直到这里它工作正常。但是现在我们有了第二个表格,可以了解更多关于伤口的信息,下次点击时也会填写,与此表格相关:

CREATE TABLE [dbo].[epadoc_mod_wound_progress] (
    [progress_id]       INT           IDENTITY (1, 1) NOT NULL,
    [wound_length]      INT           NULL,
    [wound_width]       INT           NULL,
    [wound_depth]       INT           NULL,
    [wound_surrounding] VARCHAR (500) NULL,
    [wound_consistence] VARCHAR (500) NULL,
    [wound_state]       VARCHAR (200) NULL,
    [wound_painscale]   VARCHAR (MAX) NULL,
    [wound_itch]        VARCHAR (MAX) NULL,
    PRIMARY KEY CLUSTERED ([progress_id] ASC)

使用插入方法:

 public void SaveWoundProgress(int woundLength, int woundWidth, int woundDepth, string woundSurrounding, string woundConsistence, string woundState, string woundPainScale, string woundItch)
        {
            var table = ConfigurationManager.AppSettings["woundProgressTable"];
            var insertQuery = "INSERT INTO " + table + "(wound_length,wound_width,wound_depth, wound_surrounding, wound_consistence, wound_state, wound_painscale, wound_itch) VALUES (@woundLength, @woundWidth, @woundDepth, @woundSurrounding, @woundConsistence, @woundState, @woundPainScale, @woundItch)";


            var cmd = new SqlCommand(insertQuery);

            cmd.Parameters.AddWithValue("@woundLength", woundLength);
            cmd.Parameters.AddWithValue("@woundWidth", woundWidth);
            cmd.Parameters.AddWithValue("@woundDepth", woundDepth);
            cmd.Parameters.AddWithValue("@woundSurrounding", woundSurrounding);
            cmd.Parameters.AddWithValue("@woundConsistence", woundConsistence);
            cmd.Parameters.AddWithValue("@woundState", woundState);
            cmd.Parameters.AddWithValue("@woundPainScale", woundPainScale);
            cmd.Parameters.AddWithValue("@woundItch", woundItch);
            var db = DatabaseController.getDataBaseController();

            try
            {
                var sqlcmd = db.executeSQL(cmd);
            }
            catch (SqlException e)
            {

            }
        }

还有方法

_db.SaveWoundProgress(wound_length, wound_width, wound_depth, woundArea, woundEdge, woundStatus, painStatus, itchStatus);

在上面提到的方法之后执行。

我知道如何在两个表之间创建外键,但是我们尝试的一切都失败了 - 如果我们尝试使用非 NULL 的外键集来执行它,我们会得到一个空异常。

我们尝试的示例:

CONSTRAINT [FK_epadoc_mod_wound_details] FOREIGN KEY ([wound_id])
REFERENCES [dbo].[epadoc_mod_wound_progress] ([progress_id])

如果我们这样设置外键,它就不起作用了。

我们得出的结论是,这两个方法执行时调用堆栈一定有问题 - 但我们不知道如何解决它。 也许我们必须将 INSERT-query 中的外键设置为显式变量?

我们想要实现的是细节表的wound_id作为进度表的外键,以便以后可以更改伤口(例如,如果它愈合了,用户可以重新输入新的大小等),我们可以按 ID 过滤,仅向患者显示一个伤口,而不是在单击特定伤口时同时显示所有伤口。

遗憾的是,我不是大型数据库专家,所以我希望你能听从我的解释:)。

感谢您的帮助!

【问题讨论】:

  • 删除所有隐藏错误的catch{} 块。现在你不知道这些语句中的任何一个是成功还是抛出错误。 catch{} 不会消除错误或使您的代码更健壮,这意味着您无法知道它是否有效

标签: c# sql tsql ado.net


【解决方案1】:

您的epadoc_mod_wound_progress 需要包含[wound_id] INT NOT NULL 列。这就是你的外键应该建立的,这样一个伤口可以有很多伤口进展。然后,在您的插入语句中,您将在woundDetail 表插入中生成的wound_id 插入到epadoc_mod_wound_progress

【讨论】:

  • 嘿,首先 - 感谢您的回答!所以我必须先通过 select 语句获取 id,然后使用 INSERT 输入它?或者有没有更简单的方法? :)
  • 此链接是您的最佳策略:stackoverflow.com/questions/18373461/… 使用带有插入的 executescalar 返回 ID。我会更新您的 SaveWoundDetails 方法以返回 int
  • 是的,我在此期间找到了它,我使用 SCOPE_IDENTITY() 将 ID 传递给另一个表 :) - 感谢您的帮助,它现在可以工作了! :)
【解决方案2】:

尝试添加评论,但我没有 50 声望。

据我所知,我假设您正在尝试在“主表”和“epadoc_mod_wound_progress”表之间实现一对多的关系,对吗?

如果是这样,您似乎在“epadoc_mod_wound_progress”表中没有一个字段来存储wound_id,如果您不存储wound_id,您将如何尝试创建外键?

建议epadoc_mod_wound_progress表的主键是wound_id和progress_id的串联键,wound_id也是链接到主表的外键。

【讨论】:

    【解决方案3】:

    在表epadoc_mod_wound_progress 中必须有一个wound_id INT NOT NULL 列作为外键。

    还必须将约束添加到外键表,即 1 到 n 关系的 n 侧的表。假设主表的名字是epadoc_mod_wound_details(你没有显示):

    ALTER TABLE dbo.epadoc_mod_wound_progress
    ADD CONSTRAINT FK_progress_details FOREIGN KEY (wound_id)
    REFERENCES dbo.epadoc_mod_wound_details (wound_id)
    ON DELETE CASCADE
    

    另外,通过添加ON DELETE CASCADE,当您删除伤口详细信息时,伤口详细信息的进度将自动删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多