C# 保存数据并同时检索数据的id

C# 保存数据并同时检索数据的id,c#,sql,database,visual-studio,sql-server-2019,C#,Sql,Database,Visual Studio,Sql Server 2019,我刚开始使用sql,有一个问题我已经处理了好几天了 我有两个数据表。第一个是书,第二个是作者。book表的字段: 书 图书编号(PK) 作者 书名 作者 作者(PK) 作者姓名 我想在这里做的是在书籍注册时为作者创建数据库 1-书名、作者姓名将写入Windows窗体应用程序的文本框中,并单击“保存”按钮。作者姓名将首先保存在“author”表中,并创建id作为自动pk键 2-文本框上写的“作者姓名”和作者表中相应的id将被提取 3-最后,书名和作者id将记录在“book”表中 举个例子: 要在

我刚开始使用sql,有一个问题我已经处理了好几天了

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

书 图书编号(PK)

作者

书名

作者 作者(PK)

作者姓名

我想在这里做的是在书籍注册时为作者创建数据库

1-书名、作者姓名将写入Windows窗体应用程序的文本框中,并单击“保存”按钮。作者姓名将首先保存在“author”表中,并创建id作为自动pk键

2-文本框上写的“作者姓名”和作者表中相应的id将被提取

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

举个例子:

要在Windows窗体应用程序中创建文本框,请执行以下操作:

书名:IT

作者姓名:斯蒂芬·金

点击保存按钮

作者表 AuthorID:97(自动分配)

作者姓名:斯蒂芬·金

书桌 书号:11

作者: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值“从authorName='author30'所在的作者选择authorID”转换为数据类型int时,转换失败。”

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

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

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

解决方案
SQLServer支持一个名为OUTPUT for(除其他外)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此(而非非非查询)将以插入值的2x2结果集(即数据库计算的主键和日期)进行响应。当然,您也可以在1x1模式下使用它(并执行Calar it),但通常使用SQL时,我们的目标应该是在数据集中工作

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

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

  • SQL注入风险
  • 您没有正确处理连接
  • 您应该为
    varchar
    参数使用正确的长度
我将演示如何正确地做到这一点

const string query=@”
插入作者(authorName)
价值观(@pautor);
插入书本(书名、作者)
值(@PbookName,SCOPE_IDENTITY());
";
使用(var connectionObject=newsqlconnection(connString))
使用(var commandObject=newsqlcommand(查询、连接对象))
{
commandObject.Parameters.Add(“@pautor”,SqlDbType.VarChar,100).Value=textBoxauthorName.Text;
commandObject.Parameters.Add(“@PbookName”,SqlDbType.VarChar,100)。Value=textBoxbookName.Text;
connectionObject.Open();
commandObject.ExecuteOnQuery();
}

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

警告:您的代码存在巨大的安全漏洞。它很容易受到注射攻击。你需要参数化你的陈述;永远不要将未初始化的值注入数据库。注意,我特别提到的是在
sqlcmd2
中注入值,尽管之后将is定义为参数(这是毫无意义的,因为查询不包含参数)。我在sqlcmd2部分犯了一个错误。我正在修复,我将在将来改进其他安全漏洞。我现在要做的一个简单应用是在第一个sqlcommand中使用SCOPE_IDENTITY()。所以您不需要sqlcom2。请看这里:顺便说一句,您被覆盖了您的命令对象,为每个命令创建一个新的对象。我不能完全做到这一点。是否可以为我编辑和解释代码@谢谢你的详细评论。我理解你说的话,我会考虑的。我刚开始新的生活。示例代码非常好。我很高兴听到您的问题已经解决,您可以单击'✔' 将你的答复标记为答复。它还将帮助其他人解决类似问题。
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')