0

我希望这不是那么复杂。我确实有它的工作,但我想知道这是否是最好的:

我想使用 SQL Bulk Copy 类,更具体地说是采用 IDataReader 的重载。我的数据在几个 List<> 中,所以我需要一个“翻译器”。我找到了一个通过使用扩展方法来做到这一点的方法——我认为非常优雅!它在这里列出:http ://www.differentpla.net/content/2011/01/converting-ienumerablet-idatareader我认为这是一个很好的基础?!

那里显示的代码不完整,缺少一些从未调用过的不必要的重载。我将它们添加为 NotImplementedException。完整的版本可以在最后找到。

您可以通过在 IEnumerable<> 或 List<> 上调用 AsDataReader 方法来使用该类,并将数据中的列数以及用于遍历列的函数传递给它,如下所示:

List<NodeDB> myList = new List<NodeDB>();
myList.Add(myNode1);
myBulk.WriteToServer(myList.AsDataReader(3, NodeDB.GetValue));

NodeDB 类有一些字段和一个静态(!?)方法 GetValue,它获取当前迭代的位置(!?)和列,并返回适当的项目:

static object GetValue(NodeDB nodeDB, int i) {
    object obj = null;
    switch (i) {
         case 0:
            obj = nodeDB.ID;
            break;
        case 1:
            obj = nodeDB.Latitude;
             break;
        case 2:
             obj = nodeDB.Longitude;
             break;
    }
    return obj;
}

在类中有一个带有自身实例的静态方法听起来很奇怪,我想知道是否有更好的方法。但更重要的是:我确实有几个类,比如 NodeDB,它们都有自己的特定 GetValues,组织成 List<>,每个类型都有一个 List<>。

我想将它们全部传递给一个通用的批量写入方法。

目前,我通过将不同的列表作为 IEnumberable 传递来做到这一点,然后在逐一比较它们之后将它们转换回原来的状态:

if (list is List<NodeDB>) {
} else if ( ....

在每种不同的情况下,我也需要处理正确的函数,即重复、重复和乏味 - 有没有办法从传递的 List 派生正确的 Func 参数?

如何更改我的类(从具有抽象 GetValues 的公共类派生)?我认为,所有 List<> 都可以作为 List 给出,并且所有对 GetValues 的调用都会达到它的目标。我试图这样做,但静态方法在基类中不能是抽象的。

或者我可以添加另一个参数,一个 TYPE 可能然后调用 Func 反对它?或者更改 IDataReader 扩展?

正如我所说,我迷路了......感谢您的帮助!拉尔夫

这里是带有所有接口实现的 IEnumerable 的完整 IDataReader 扩展:

using System;
using System.Collections.Generic;
using System.Data;

static class DataReaderExtensions {
    public static IDataReader AsDataReader<TSource>(this IEnumerable<TSource> source, int fieldCount, Func<TSource, int, object> getValue) {
        return new EnumerableDataReader<TSource>(source.GetEnumerator(), fieldCount, getValue);
        //return EnumerableDataReader.Create(source, fieldCount, getValue);
    }
}

//internal static class EnumerableDataReader {
//    public static IDataReader Create<TSource>(IEnumerable<TSource> source, int fieldCount, Func<TSource, int, object> getValue) {
//        return new EnumerableDataReader<TSource>(source.GetEnumerator(), fieldCount, getValue);
//    }
//}

internal class EnumerableDataReader<TSource> : IDataReader {
    private readonly IEnumerator<TSource> _source;
    private readonly int _fieldCount;
    private readonly Func<TSource, int, object> _getValue;

    internal EnumerableDataReader(IEnumerator<TSource> source, int fieldCount, Func<TSource, int, object> getValue) {
        _source = source;
        _getValue = getValue;
        _fieldCount = fieldCount;
    }

    public void Dispose() {
        // Nothing.
    }

    public string GetName(int i) {
        throw new NotImplementedException();
    }

    public string GetDataTypeName(int i) {
        throw new NotImplementedException();
    }

    public Type GetFieldType(int i) {
        throw new NotImplementedException();
    }

    public object GetValue(int i) {
        return _getValue(_source.Current, i);
    }

    public int GetValues(object[] values) {
        throw new NotImplementedException();
    }

    public int GetOrdinal(string name) {
        throw new NotImplementedException();
    }

    public int FieldCount {
        get { return _fieldCount; }
    }

    object IDataRecord.this[int i] {
        get { throw new NotImplementedException(); }
    }

    object IDataRecord.this[string name] {
        get { throw new NotImplementedException(); }
    }

    public void Close() {
        throw new NotImplementedException();
    }

    public DataTable GetSchemaTable() {
        throw new NotImplementedException();
    }

    public bool NextResult() {
        throw new NotImplementedException();
    }

    public bool Read() {
        return _source.MoveNext();
    }

    public int Depth { get; private set; }
    public bool IsClosed { get; private set; }
    public int RecordsAffected { get; private set; }

    public bool IsDBNull(int i) {
        throw new NotImplementedException();
    }

    public IDataReader GetData(int i) {
        throw new NotImplementedException();
    }

    public DateTime GetDateTime(int i) {
        throw new NotImplementedException();
    }

    public Decimal GetDecimal(int i) {
        throw new NotImplementedException();
    }

    public String GetString(int i) {
        throw new NotImplementedException();
    }

    public Double GetDouble(int i) {
        throw new NotImplementedException();
    }

    public float GetFloat(int i) {
        throw new NotImplementedException();
    }

    public Int64 GetInt64(int i) {
        throw new NotImplementedException();
    }

    public Int32 GetInt32(int i) {
        throw new NotImplementedException();
    }

    public Int16 GetInt16(int i) {
        throw new NotImplementedException();
    }

    public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) {
        throw new NotImplementedException();
    }

    public Guid GetGuid(int i) {
        throw new NotImplementedException();
    }

    public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) {
        throw new NotImplementedException();
    }

    public Char GetChar(int i) {
        throw new NotImplementedException();
    }

    public Byte GetByte(int i) {
        throw new NotImplementedException();
    }

    public Boolean GetBoolean(int i) {
        throw new NotImplementedException();
    }

}
4

1 回答 1

2

一种可能的解决方案是制作GetValue非静态并像这样传递它:

List<NodeDB> myList = new List<NodeDB>();
myList.Add(myNode1);
myBulk.WriteToServer(myList.AsDataReader(3, (n,i)=>n.GetValue(i)));

GetValue方法将如下所示:

public object GetValue(int i) 
{
    object obj = null;
    switch (i) 
    {
        case 0:
            obj = this.ID;
            break;
        case 1:
            obj = this.Latitude;
            break;
        case 2:
            obj = this.Longitude;
            break;
    }
    return obj;
}
于 2013-08-15T16:24:58.960 回答