2

我有一个字典定义为的代码:

Dictionary<int, StringBuilder> invoiceDict = new Dictionary<int, StringBuilder>();

Dictionary 中的每个 KeyValuePair 中的每个 Value 实际上是当前创建的三个单独的值,如下所示:

invoiceDict.Add(pdfCount+i, new StringBuilder(invoiceID.Groups[1].ToString() + "|" + extractFileName + "|" + pdfPair.Key));

如您所见,三个值由“|”分隔。字典中的“行”数可以在 600-1200 之间。我想使用一个表值参数在一次操作中在我的 SQL Server 2008 DB 中获取所有这些。

表值参数定义如下:

CREATE TYPE dbo.BatchSplitterInvoices AS TABLE
(
    InvoiceID varchar(24),
    NotePath varchar(512),
    BatchID varchar(50)
)

CREATE PROCEDURE dbo.cms_createBatchSplitterInvoices (
  @Invoices dbo.BatchSplitterInvoices READONLY,
  @StaffID int
)

从字典中获取可以传递给表值参数的东西的最佳方法是什么?我应该使用字典以外的东西吗?或者,我是否需要将 Dictionary 解析为另一个更好的数据结构?

SqlParameter invoicesParam = cmd.Parameters.AddWithValue("@Invoices", invoiceDict.Values);
invoicesParam.SqlDbType = SqlDbType.Structured;

谢谢。

4

4 回答 4

1

由于围绕 TVP 的文档有些差劲(需要的不仅仅是 IEnumerable),并且无论如何都必须解析字典的内容,我决定将字典循环到 DataTable 中,这似乎是提供 TVP 的首选对象.

于 2009-09-21T18:45:15.903 回答
1

@narayanamarthi 和 @ChrisGessler 在使用IEnumerable<SqlDataRecord>界面而不是 DataTable 方面都在正确的轨道上。将集合复制到 DataTable 只是浪费 CPU 和内存而没有任何收获。但是迭代器可以与集合分开。

所以一些注意事项:

  • AddWithValue创建SqlParameters时不要使用。这只是一个坏习惯
  • 不要将 TVP 中所需的 3 个不同值连接到 String 或 StringBuilder。TVP 的全部目的是传递强类型记录,因此将字段序列化为 CSV 列表会破坏目的。而是使用 Chris 推荐的 Invoice 类。
  • 替换你invoiceDict.Add(...)List<Invoice>.Add(new Invoice(...));
  • 创建一个迭代集合的方法:

    private static IEnumerable<SqlDataRecord> SendRows(List<Invoice> Invoices)
    {
      SqlMetaData[] _TvpSchema = new SqlMetaData[] {
        new SqlMetaData("InvoiceID", SqlDbType.Int),
        new SqlMetaData("NotePath", SqlDbType.VarChar, 512),
        new SqlMetaData("BatchID", SqlDbType.VarChar, 50)
      };
      SqlDataRecord _DataRecord = new SqlDataRecord(_TvpSchema);
    
      foreach(Invoice _Invoice in Invoices)
      {
        _DataRecord.SetInt32(0, _Invoice.Id);
        _DataRecord.SetString(1, _Invoice.NotePath);
        _DataRecord.SetString(2, _Invoice.BatchId);
        yield return _DataRecord;
      }
    }
    
  • 声明参数如下:

    SqlParameter _InvoiceParam = cmd.Parameters.Add("@Invoices", SqlDbType.Structured);
    _InvoiceParam.Value = SendRows(Invoices);
    

对于一般的 TVP,我在以下两个答案中有额外的注释和链接:

于 2015-02-24T17:32:35.333 回答
0

在保存您的集合的类上实现 IEnumerable 接口,然后为 IEnemerable 显式实现 GetEnumerator 方法将达到目的。在http://lennilobel.wordpress.com/2009/07/29/sql-server-2008-table-valued-parameters-and-c-custom-iterators-a-match-made-in-heaven有一篇文章/。请通过这个

于 2009-10-26T04:53:26.383 回答
0

您需要IEnumerable<SqlDataRecord>在自定义集合对象上实现。在您的情况下,您应该更改您的Dictionary<int, StringBuilder>toList<Invoice>List<Tuple<int, string, int>>

例如:

class Invoice
{
  public int Id { get; set; }
  public string NotePath { get; set; }
  public int BatchId { get; set; }
}

class InvoiceCollection : List<Invoice>, IEnumerable<SqlDataRecord>
{
  IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
  {
    SqlDataRecord r - new SqlDataRecord(
      new SqlMetaData("InvoiceId", SqlDataType.Int), 
      new SqlMetaData("NotePath", SqlDataType.VarChar), 
      new SqlMetaData("BatchId", SqlDataType.Int)
    );

    foreach(var item in this)
    {
      r.SetInt32(0, item.Id);
      r.SetString(1, item.NotePath);
      r.SetInt32(2, item.BatchId);
      yield return r;
    }
}

然后只需将自定义列表传递给SqlParameter

SqlCommand cmd = new SqlCommand("dbo.InvoiceInsUpd", connection);
cmd.CommandType = CommandType.StoredProcedure;

SqlParameter sqlParam = cmd.Parameters.AddWithValue("@Invoices", invoices);
sqlParam.SqlDbType = SqlDbType.Structured;
于 2013-02-26T13:16:33.327 回答