Supplying stream as a source of data for a binary column when SqlBulkCopy is used

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-06 09:36:10

Not sure this is documented anywhere, but if do short inspection of SqlBulkCopy source code you may find out that it treats different data readers in different ways. First, SqlBulkCopy does support streaming and GetStream, but you might notice that IDataReader interface does not contain GetStream method. So when you feed custom IDataReader implementation to SqlBulkCopy - it will not treat binary columns as streamed and will not accept values of Stream type.

On the other hand - DbDataReader does have this method. If you feed SqlBulkCopy an instance of DbDataReader-inherited class - it will treat all binary columns in streamed manner and it will call DbDataReader.GetStream.

So to fix your problem - inherit from DbDataReader like this:

class TestDataReader : DbDataReader
{
    public override bool IsDBNull(int ordinal) {
        return false;
    }

    public override int FieldCount { get; } = 2;
    int rowCount = 1;

    public override bool HasRows { get; } = true;
    public override bool IsClosed { get; } = false;

    public override bool Read()
    {
        return (rowCount++) < 3;
    }

    public override object GetValue(int ordinal) {
        switch (ordinal) {
            // do not return anything for binary column here - it will not be called
            case 0:
                return rowCount;
            default:
                throw new Exception();
        }
    }

    public override Stream GetStream(int ordinal) {
        // instead - return your stream here
        if (ordinal == 1)
            return new MemoryStream(new byte[] {0x01, 0x23, 0x45, 0x67, 0x89});
        throw new Exception();
    }
    // bunch of irrelevant stuff

}

See following code

static int SendOrders(int totalToSend)
    {
      using (SqlConnection con = new SqlConnection(connectionString))
      {
        con.Open();
        using (SqlTransaction tran = con.BeginTransaction())
        {
          var newOrders =
                  from i in Enumerable.Range(0, totalToSend)
                  select new Order
                  {
                    customer_name = "Customer " + i % 100,
                    quantity = i % 9,
                    order_id = i,
                    order_entry_date = DateTime.Now
                  };

          SqlBulkCopy bc = new SqlBulkCopy(con,
            SqlBulkCopyOptions.CheckConstraints |
            SqlBulkCopyOptions.FireTriggers |
            SqlBulkCopyOptions.KeepNulls, tran);

          bc.BatchSize = 1000;
          bc.DestinationTableName = "order_queue";
          bc.WriteToServer(newOrders.AsDataReader()); 

          tran.Commit();
        }
        con.Close();

      }

      return totalToSend;

    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!