65.9K
CodeProject 正在变化。 阅读更多。
Home

IDataReader 实现 + SqlBulkCopy

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (10投票s)

2013 年 5 月 22 日

CPOL

2分钟阅读

viewsIcon

55208

使用 SqlBulkCopy 类说明的 IDataReader 实现

介绍  

我将展示如何实现 IDataReader 接口。我还会通过展示如何使用 SqlBulkCopy 类将文件中的数据插入到 SQL Server 表中来阐述其用法。

背景 

IDataReader 接口有很多方法,并且还要求你实现 IDataRecord(很多方法x2 Smile | <img src=)。也许正因为如此,我看到的所有的 IDataReader 实现通常比它应该的要复杂得多。

下面介绍的方法仅实现了读取文件数据并将其插入到表中的任务所需的方法。 尽量保持代码简单高效。

使用代码

首先,让我们说明 IDataReader 实现(我将称之为 MyFileDataReader)的用法。

为此,我将使用 SqlBulkCopy 类,该类“让你能够有效地将数据从另一个源批量加载到 SQL Server 表中”。“另一个源”可以是另一个表,或者在本例中,一个 DataReader。

使用 DataReader 实现,我们可以按照以下方式将文件中的数据插入到 sql server 表中:

using (MyFileDataReader reader = new MyFileDataReader(@"C:\myfile.txt"))
{
  SqlBulkCopy bulkCopy = new SqlBulkCopy(connection);
  bulkCopy.DestinationTableName = "[serv].[dbo].[my_test_table]";
  bulkCopy.BatchSize = 10000;

  bulkCopy.WriteToServer(reader);

  bulkCopy.Close();

}  

该 reader 包含一个流和其他成员,以帮助从文件中读取数据

public class MyFileDataReader : IDataReader
{
    protected StreamReader Stream { get; set; }
    protected object[] Values;
    protected bool Eof { get; set; }
    protected string CurrentRecord { get; set; }
    protected int CurrentIndex { get; set; }

    public MyFileDataReader(string fileName)
    {
        Stream = new StreamReader(fileName);
        Values = new object[this.FieldCount];
    }  

SqlBulkCopy 类只需调用几个方法即可完成工作。为了简化这里的实现,我将假设将接收来自文件的数据的表只有 3 列:主键和 2 个字符串列。 并且:文件是固定列格式的,并且有两列:第一列宽度为 12,第二列宽度为 40。 这样说来,我们可以这样做:

public void Close()
{
    Array.Clear(Values, 0, Values.Length);
    Stream.Close();
    Stream.Dispose();
}

public int Depth
{
    get { return 0; }
}

public DataTable GetSchemaTable()
{// avoid to implement several methods if your scenario do not demand it

    throw new NotImplementedException();
}

public bool IsClosed
{
    get { return Eof; }
}

public bool NextResult()
{
    return false;
}

public bool Read()
{
    CurrentRecord = Stream.ReadLine();
    Eof = CurrentRecord == null;

    if (!Eof)
    {
        Fill(Values);
        CurrentIndex++;
    }

    return !Eof;
}

private void Fill(object[] values)
{ // by default, the first position of the array holds the value that will be  
   // inserted at the first column of the table, and so on
   // lets assume here that the primary key is auto-generated
    values[0] = null;
    values[1] = CurrentRecord.Substring(0, 12).Trim();
    values[2] = CurrentRecord.Substring(12, 40).Trim();
} // if the file is csv we could do a Split instead of Substring operations

public int RecordsAffected
{
    get { return -1; }
} 

要实现 IDataReader,还必须实现 IDisposableIDataRecord 接口。

IDataRecord 强制你实现很多方法。 但在这种情况下,有一些方法实现是我们无法避免的:

public int FieldCount
{
    get { return 3; }
}

public IDataReader GetData(int i)
{
    if (i == 0)
        return this;

    return null;
}

public string GetDataTypeName(int i)
{
    return "String";
}

public string GetName(int i)
{
    return Values[i].ToString();
}

public string GetString(int i)
{
    return Values[i].ToString();
}

public object GetValue(int i)
{
    return Values[i];
}

public int GetValues(object[] values)
{
    Fill(values);

    Array.Copy(values, Values, this.FieldCount);

    return this.FieldCount;
}

public object this[int i]
{
    get { return Values[i]; }
}  

在这种情况下,不需要实现 IDataRecord 的其他方法。

IDisposable 只有 Dispose 方法,可用于关闭 reader 并释放所有使用的资源。

值得关注的点

在我的测试中,这被证明是从大文件读取数据并将其内容插入到 SQL Server 表中的一种有效方法。 上面介绍的 IDataReader 实现非常简单。 可以通过添加异常处理和更多数据类型支持来改进它。 也可以将其调整为支持其他文件格式(例如,CSV 或 XML)。

© . All rights reserved.