#初めに
C#で Bulk Insert のサンプルを作成して利用しているが、データの変換が必要な場合、DataSetにいれる必要がでてメモリが必要になる。
IEnumerableを使えば、yield return でデータを返すとメモリをあまり使用せずに実行ができる。
調べるとブログ「Converting IEnumerable to IDataReader」を見つけた。
SqlBulkCopy を使うための最小限のIDataReaderの実装が載っていて大変参考になった。
#サンプルコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Threading.Tasks;
using SampleIDataReader.Properties;
namespace SampleIDataReader
{
static class DataReaderExtensions
{
public static IDataReader AsDataReader<TSource>(this
IEnumerable<TSource> source)
{
return EnumerableDataReader.Create(source);
}
}
internal static class EnumerableDataReader
{
public static IDataReader Create<TSource>(IEnumerable<TSource>
source)
{
return new EnumerableDataReader<TSource>(source);
}
}
internal class EnumerableDataReader<TSource> : IDataReader
{
private readonly IEnumerator<TSource> _source;
private readonly List<PropertyInfo> listProp = new
List<PropertyInfo>();
internal EnumerableDataReader(IEnumerable<TSource> source)
{
_source = source.GetEnumerator();
foreach (var prop in typeof(TSource).GetProperties())
{
listProp.Add(prop);
}
}
public bool Read()
{
return _source.MoveNext();
}
public void Close()
{
}
public void Dispose()
{
}
public int FieldCount
{
get { return listProp.Count; }
}
public object GetValue(int i)
{
return listProp[i].GetValue(_source.Current);
}
public int Depth
{
get { throw new NotImplementedException(); }
}
// 残りのメソッドもDepthと同様 NotImplementedException を発生させている
}
class SampleTable
{
public int Field1 { get; set; }
public string Field2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var arr = new SampleTable[]
{
new SampleTable{Field1 = 1, Field2 = "Field1"},
new SampleTable{Field1 = 2, Field2 = "Field2"},
new SampleTable{Field1 = 3, Field2 = "Field3"},
};
using (var bc = new
SqlBulkCopy(Settings.Default.xxxConnectionString))
{
bc.DestinationTableName = "dbo.SampleTable";
bc.WriteToServer(arr.AsDataReader());
}
}
}
}