sql-server - 如何基于使用 ASP.NET Core 调用的存储过程插入具有多个外键记录的主键记录
问题描述
我正在构建一个基于 ASP.NET Core 的内容/知识库系统。一个页面将显示一个带有多个下拉菜单的富文本编辑器(下拉菜单的数量不受限制,但很可能不超过 10 个)。
例如,富文本编辑器中的内容是关于在热带环境中的淤泥土中种植有机咖啡。在此示例中,将有 3 个下拉框:
- 作物是咖啡
- 气候属热带
- 土壤类型为淤泥
点击提交时,页面会将内容存储在内容表中,并在分类-内容表中添加三条记录,该表是分类值与内容之间的nm关系表。
在 SQL 中,我想使用单个事务来执行此操作,以确保全部插入或不插入。
我正在考虑创建一个临时表并首先在其中插入 3 个值。然后使用存储过程调用以添加内容并将临时表中的记录作为单个事务复制到分类内容表中。
这是因为我没有看到将 C# 中的值数组放入存储过程的选项。有什么建议么?
解决方案
您可以使用表值参数,也可以使用 Begin、Commit 和 RollBack Transaction。您可以执行以下操作
CREATE TYPE [dbo].[Content] AS TABLE
(
[Column1] VARCHAR (1) NOT NULL,
[Column2] VARCHAR (100) NOT NULL,
.
.
.
[ColumnN] VARCHAR (30) NOT NULL
)
CREATE TYPE [dbo].[ContentClassification] AS TABLE
(
[Column1] VARCHAR (1) NOT NULL,
[Column2] VARCHAR (100) NOT NULL,
.
.
.
[ColumnN] VARCHAR (30) NOT NULL
)
CREATE PROCEDURE [dbo].[USP_CONTENT_INSERT]
@Content as [Content] READONLY,
@ContentClassification as [ContentClassification] READONLY,
@ErrorStatus int Out
AS
BEGIN TRY
BEGIN TRANSACTION
-- Insert in to Content
INSERT INTO [tbl_ContentTable]
( [Column1], [Column2],... [ColumnN] )
SELECT [Column1], [Column2],..[ColumnN] FROM @Content
-- Insert in to ContentClassification
INSERT INTO [tbl_ContentClassification]
( [Column1], [Column2],... [ColumnN] )
SELECT [Column1], [Column2],...[ColumnN] FROM @ContentClassification
set @OutStatus = 1;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF(@@TRANCOUNT > 0)
ROLLBACK TRANSACTION;
set @OutStatus = -1;
END CATCH
以上将确保为给定的父母插入所有受抚养人。如果发生错误,它将是一个回滚。
或者,您也可以在 C# 代码中使用连接对象的 BeginTransaction 对象执行相同操作。下面是来自 MSDN https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.begintransaction?view=netframework-4.8的代码片段
private static void ExecuteSqlTransaction(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction("SampleTransaction");
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"Insert into tbl_ContentTable (Column1, Column2, ... ColumnN) VALUES (V1, V2,...VN)";
command.ExecuteNonQuery();
command.CommandText =
"Insert into tbl_ContentTable (Column1, Column2, ... ColumnN) VALUES (V1, V2,...VN)";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
希望这可以帮助!
推荐阅读
- c# - 内部列表不使用 httpclient c# 在服务器上填充
- hyperledger-fabric - Hyperledger Fabric 对等通道更新失败
- postman - 邮递员 url 替换 env。金丝雀 v8.7.0 中的变量不正确
- sql - 如何在 T-SQL 中插入另一个表中的列?
- node.js - 根据语言从不同文件夹快速提供静态服务
- reactjs - 使用 react-router 在应用程序中使用 react-router 反应组件
- arrays - 我正在尝试读取数据,对其进行排序,以便确定数据集的峰值
- java - 未应用 ArrayList 的默认大小
- java - BasicLookupStrategy 使用不正确的查询
- matplotlib - Matplotlib:当用鼠标调整图形大小或我们切换到全屏模式时,如何避免刻度间距的扩大?