【问题标题】:Saving data and retrieving the id of the data at the same time同时保存数据和检索数据的id
【发布时间】:2021-06-12 13:50:40
【问题描述】:

我刚启动 sql,遇到一个问题,我已经处理了好几天了。

我有两个数据表。第一个是书,第二个是作者。 book 表的字段:

图书 ID (PK)

作者 ID

书名

...

作者

作者 ID (PK)

作者姓名

我在这里要做的是在图书注册时为作者创建数据库。

1-书名,作者姓名将写入Windows表单应用程序的文本框中,并单击保存按钮。作者名字会先保存在'author'表中,并创建作为自动pk key的id。

2-文本框上写的“作者姓名”和作者表中对应的id会被取走。

3- 最后,书名和作者id将记录在“书”表中。

举个例子:

到 Windows 表单应用程序中的文本框:

书名:IT

作者姓名:斯蒂芬·金

点击保存按钮。

作者表

AuthorID:97(自动分配)

作者姓名:斯蒂芬·金

书桌

图书编号:11

作者 ID:97

书名:IT

简而言之,只需单击一下,即可同时拥有作者和书籍记录和数据库。

我尝试了很多方法,但我无法存储我获取的作者 ID。

string sqlcom1 = "INSERT INTO author (authorName) VALUES(@Pauthor)";
            commandObject = new SqlCommand(sqlcom1, connectionObject );
            commandObject.Parameters.AddWithValue("@Pauthor", textBoxauthorName.Text);

string sqlcom2 = "SELECT authorID FROM author WHERE authorName='" + textBoxauthorName.Text + "'");
            commandObject = new SqlCommand(sqlcom2 , connectionObject );
            

string sqlcom3 = "INSERT INTO book (bookName,authorID) VALUES(@PbookName,@PauthorID)";
            commandObject = new SqlCommand(sqlcom3, connectionObject);
            commandObject.Parameters.AddWithValue("@PbookName", textBoxbookName.Text);
            commandObject.Parameters.AddWithValue("@PauthorID", sqlcom2);

connectionObject.Open();
commandObject.ExecuteNonQuery();
connectionObject.Close();

错误: '将 nvarchar 值 'SELECT authorID FROM author WHERE authorName='author30'' 转换为数据类型 int 时转换失败。'

author30 --> 我在作者姓名的文本框中输入的值。

注意:我可以看到,通过注册到 author 表,名称会自动分配 id。正在向作者表注册。

作者 ID 与图书表中的作者 ID 相关联。

【问题讨论】:

  • 警告:您的代码存在巨大安全漏洞。它很容易受到注入攻击。您需要参数化您的陈述;永远不要将未经处理的值注入您的数据库。
  • 注意,我特意说的是sqlcmd2 注入值的地方,尽管之后将 is 定义为参数(这是没有意义的,因为查询不包含参数)。
  • 我在sqlcmd2部分犯了一个错误。我正在修复我将在将来学习时改进其他安全漏洞。我现在想做的一个简单的应用程序
  • 在您的第一个 sql 命令中使用 SCOPE_IDENTITY()。所以你不需要sqlcom2。见这里:stackoverflow.com/a/18373514/448100 btw,你被覆盖了你的命令对象,为每个命令创建一个新对象。
  • 我不能完全做到。是否可以为我编辑和解释代码? @ibram

标签: c# sql database visual-studio sql-server-2019


【解决方案1】:

解决方案

            connectionObject.Open();
            string sqlcom1 = "INSERT INTO author (authorName) VALUES(@Pauthor); SELECT SCOPE_IDENTITY()";
            commandObject= new SqlCommand(sqlcom1, connectionObject);
            commandObject.Parameters.AddWithValue("@Pauthor", textBoxauthorName.Text);
            string SolutionVariable = commandObject.ExecuteScalar().ToString();
            

            string sqlcom3 = "INSERT INTO book (bookName,authorID) VALUES(@PbookName,@PauthorID)";
            commandObject = new SqlCommand(sqlcom3, connectionObject);
            commandObject.Parameters.AddWithValue("@PbookName", textBoxbookName.Text);
            commandObject.Parameters.AddWithValue("@PauthorID", SolutionVariable);

            
            commandObject.ExecuteNonQuery();
            connectionObject.Close();

【讨论】:

  • 很高兴听到您的问题已经解决,您可以点击“✔”将您的回复标记为答案。它还将帮助其他人解决类似的问题。
【解决方案2】:

您需要使用SCOPE_IDENTITY() 来获取插入的ID,并将其传递给另一个表。在单个命令中执行此操作。

您的代码还有许多其他问题:

  • SQL 注入风险
  • 您没有正确处理连接
  • 您应该为varchar 参数使用正确的长度

我将演示如何正确地做到这一点

const string query = @"
INSERT INTO author (authorName)
VALUES(@Pauthor);

INSERT INTO book (bookName, authorID)
VALUES(@PbookName, SCOPE_IDENTITY());
";

using(var connectionObject = new SqlConnection(connString))
using(var commandObject = new SqlCommand(query, connectionObject))
{
    commandObject.Parameters.Add("@Pauthor", SqlDbType.VarChar, 100).Value = textBoxauthorName.Text;
    commandObject.Parameters.Add("@PbookName", SqlDbType.VarChar, 100).Value = textBoxbookName.Text;
    connectionObject.Open();
    commandObject.ExecuteNonQuery();
}

如果您有多行,则需要使用OUTPUT 子句。同样,您可以在单个批处理命令中执行此操作,只需先将其发送到表变量即可。

【讨论】:

  • 我明白你的意思,我会考虑的。我刚开始新。一个示例代码非常好。
【解决方案3】:

SQLServer 支持一个名为 OUTPUT 的子句,用于(除其他外)INSERT 语句,它允许您检索所有插入值的一组行。这比选择 SCOPE_IDENTITY 更有用,因为它允许您检索多个值;例如,您可以插入 N 行,并检索每个插入行的 O 列

INSERT INTO T(CreateDate,A,B,C) --imagine that T has a PK int autonumber
OUTPUT inserted.PK,inserted.CreateDate
VALUES (GetUtcDate(),'A','BB','CCC'),(GetUtcDate(),'A2','BB2','CCC2')

ExecuteReader()ing this(而不是 NonQuery)将响应插入值的 2x2 结果集 - PK 和 DB 计算的日期。当然,您也可以在 1x1 模式下使用它(并执行标量),但通常使用 SQL,我们应该旨在处理数据集

【讨论】:

  • 感谢您提供详细的 cmets。
猜你喜欢
  • 1970-01-01
  • 2018-05-28
  • 2021-05-07
  • 2023-03-29
  • 2023-04-08
  • 1970-01-01
  • 2014-11-05
  • 2021-07-12
  • 2015-05-30
相关资源
最近更新 更多