gpt4 book ai didi

sql-server - 将 Dictionary 传递给存储过程 T-SQL

转载 作者:行者123 更新时间:2023-12-02 14:07:06 24 4
gpt4 key购买 nike

我有 mvc 应用程序。在行动中我有Dictionary<string,int>Key是 ID 和 Value是排序顺序号。我想创建存储过程,该存储过程将获取 key(id) 在数据库中找到此记录并保存 orderNumber专栏作者 value来自字典。我想一次调用存储过程并向其传递数据,而不是多次调用来更新数据。

你有什么想法吗?谢谢!

最佳答案

使用 TVP 的公认答案通常是正确的,但需要根据传入的数据量进行一些澄清。对于较小的数据集,使用 DataTable 很好(更不用说快速且简单),但对于较大的数据集设置它不会缩放,因为它通过将数据集放置在 DataTable 中来复制数据集,只是为了将其传递到 SQL Server。因此,对于较大的数据集,可以选择流式传输任何自定义集合的内容。唯一真正的要求是您需要根据 SqlDb 类型定义结构并迭代集合,这两个步骤都是相当简单的步骤。

下面显示了最小结构的简单概述,这是我在How can I insert 10 million records in the shortest time possible?上发布的答案的改编。 ,它处理从文件导入数据,因此略有不同,因为数据当前不在内存中。从下面的代码中可以看出,这种设置并不过分复杂,而且高度灵活、高效且可扩展。

SQL 对象#1:定义结构

-- First: You need a User-Defined Table Type
CREATE TYPE dbo.IDsAndOrderNumbers AS TABLE
(
ID NVARCHAR(4000) NOT NULL,
SortOrderNumber INT NOT NULL
);
GO

SQL 对象#2:使用结构

-- Second: Use the UDTT as an input param to an import proc.
-- Hence "Tabled-Valued Parameter" (TVP)
CREATE PROCEDURE dbo.ImportData (
@ImportTable dbo.IDsAndOrderNumbers READONLY
)
AS
SET NOCOUNT ON;

-- maybe clear out the table first?
TRUNCATE TABLE SchemaName.TableName;

INSERT INTO SchemaName.TableName (ID, SortOrderNumber)
SELECT tmp.ID,
tmp.SortOrderNumber
FROM @ImportTable tmp;

-- OR --

some other T-SQL

-- optional return data
SELECT @NumUpdates AS [RowsUpdated],
@NumInserts AS [RowsInserted];
GO

C# 代码,第 1 部分:定义迭代器/发送器

using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using Microsoft.SqlServer.Server;

private static IEnumerable<SqlDataRecord> SendRows(Dictionary<string,int> RowData)
{
SqlMetaData[] _TvpSchema = new SqlMetaData[] {
new SqlMetaData("ID", SqlDbType.NVarChar, 4000),
new SqlMetaData("SortOrderNumber", SqlDbType.Int)
};
SqlDataRecord _DataRecord = new SqlDataRecord(_TvpSchema);
StreamReader _FileReader = null;

// read a row, send a row
foreach (KeyValuePair<string,int> _CurrentRow in RowData)
{
// You shouldn't need to call "_DataRecord = new SqlDataRecord" as
// SQL Server already received the row when "yield return" was called.
// Unlike BCP and BULK INSERT, you have the option here to create an
// object, do manipulation(s) / validation(s) on the object, then pass
// the object to the DB or discard via "continue" if invalid.
_DataRecord.SetString(0, _CurrentRow.ID);
_DataRecord.SetInt32(1, _CurrentRow.sortOrderNumber);

yield return _DataRecord;
}
}

C# 代码,第 2 部分:使用迭代器/发送器

public static void LoadData(Dictionary<string,int> MyCollection)
{
SqlConnection _Connection = new SqlConnection("{connection string}");
SqlCommand _Command = new SqlCommand("ImportData", _Connection);
SqlDataReader _Reader = null; // only needed if getting data back from proc call

SqlParameter _TVParam = new SqlParameter();
_TVParam.ParameterName = "@ImportTable";
// _TVParam.TypeName = "IDsAndOrderNumbers"; //optional for CommandType.StoredProcedure
_TVParam.SqlDbType = SqlDbType.Structured;
_TVParam.Value = SendRows(MyCollection); // method return value is streamed data
_Command.Parameters.Add(_TVParam);
_Command.CommandType = CommandType.StoredProcedure;

try
{
_Connection.Open();

// Either send the data and move on with life:
_Command.ExecuteNonQuery();
// OR, to get data back from a SELECT or OUTPUT clause:
SqlDataReader _Reader = _Command.ExecuteReader();
{
Do something with _Reader: If using INSERT or MERGE in the Stored Proc, use an
OUTPUT clause to return INSERTED.[RowNum], INSERTED.[ID] (where [RowNum] is an
IDENTITY), then fill a new Dictionary<string, int>(ID, RowNumber) from
_Reader.GetString(0) and _Reader.GetInt32(1). Return that instead of void.
}
}
finally
{
_Reader.Dispose(); // optional; needed if getting data back from proc call
_Command.Dispose();
_Connection.Dispose();
}
}

关于sql-server - 将 Dictionary<string,int> 传递给存储过程 T-SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19957132/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com