【问题标题】:reading from IDbCommand using an inherited custom IDataReader使用继承的自定义 IDataReader 从 IDbCommand 读取
【发布时间】:2015-11-29 19:15:59
【问题描述】:

我做了一个自定义类继承IDataReader并成功 使用 C# 对象而不是 DataTable 的自定义类实现了自定义 ServerWriter sqlBulkCopy

正如我所怀疑的那样,这被证明是一种更有效的方法。

现在我正在尝试Read,但我遇到了一些问题

这是IDataReader

// get Server Data Table Object IDataReader
public class GetSDTOIDataReaderM : IDataReader
{
   //private IEnumerator<MyTestObject> enumerator = null;

   public MySqlDbTableObject.Raw.SqlDbTableM propSqlTbl { get; set; }

   // implementing relevant GetValue(), filedCount() and Read()
   // this is how I did with WriteToServer
   public bool Read()
   {
       return ++this.ReaderRowsCount < this.propSqlTbl.Table.ElementAt(0).Row.Count;
   }
}

对象完全映射为其对应的 SqlTable。

在我的自定义 IDataReader 上将 SqlCommand 设置为 ExecuteReader() 不起作用,所以我尝试了 IDbCommand 然后它确实编译了,但仍然在尝试阅读时 我收到一个错误:

无法将“System.Data.SqlClient.SqlDataReader”类型的对象转换为 输入“GetSDTOIDataReaderM”

this.propComunicator.AsGetSDTOCom().SqlCmd.Connection.Open();
//this is the line of the error
using (this.propComunicator.AsGetSDTOCom().SDTOIDataReader = (Raw.Comunicator.Raw.GetSDTOIDataReaderM)this.propComunicator.AsGetSDTOCom().SqlCmd.ExecuteReader())
{

}

写入服务器确实有效,如何使用Read 正确实现它?

更新

关于我的模块的更多信息

public class TransManSF
{
    public enum CommunicatorTypeS { Reader, Adapter, GetSDTOReaderA, SqlBcpyIDataReaderM };
    public enum DbIntreactorTypeS { TableObject, TableRowObject, Sproc, SqlCmd };
    public enum SqlCmdActionS { NotSet, SELECT, INSERT, UPDATE, DROP };
    public enum SqlCmdStrSelModeS { Single, RecentEfected, count, All, Top10, Top100, Top1000 };
    public enum SqlCmdStrSelOrderByS { NotSet = 0, Asc = 1, Desc = 2 };
    public enum SqlCmdStrSetterModeS { Single, Multi};
    public enum STDOTypeS { NotSet, ServerWriter, ServerTableGetter, ServerBiDerctional }
    public enum SprocTypeS { Sproc, TvPSrpoc }
    public enum TransExecActionTypeS { WriteToServer, GetTable }
}

public static TransMan.Raw.ComunicatorCLF.BulkCopyComSCL AsBulkCopyCom(this TransMan.Raw.ComunicatorCLF.ComunicatorM SelfCom)
{
    return (TransMan.Raw.ComunicatorCLF.BulkCopyComSCL)SelfCom;
}

virtual public void ExecuteTransaction(AppMods.DataBase.TransManSF.TransExecActionTypeS parSelectedTransType, TransManSF.SqlCmdStrSelOrderByS parExecOrderByS, int OrderByOrdinal = 0)
{
    if (parSelectedTransType == AppMods.DataBase.TransManSF.TransExecActionTypeS.WriteToServer)
        using (this.propComunicator.AsBulkCopyCom().Conn)
        {
            this.propComunicator.AsBulkCopyCom().Conn.Open();
            using (var IDRdrServerWriter = this.propComunicator.AsBulkCopyCom().ServerWriter)
            {
                var Eng = this.propExecuter.AsBulkCopyExec().Engine;
                Eng.BulkCopyTimeout = 240;
                Eng.WriteToServer(IDRdrServerWriter);

            }
            this.propComunicator.AsBulkCopyCom().Conn.Close();
        }
    else if (parSelectedTransType == AppMods.DataBase.TransManSF.TransExecActionTypeS.GetTable)
    {
        var DreaderCom = this.propComunicator.AsDReaderCom();
        using (DreaderCom.SqlCmd.Connection)
        {
            DreaderCom.SqlCmd.Connection.Open();
            using (DreaderCom.Driver = DreaderCom.SqlCmd.ExecuteReader())
            {
                if (DreaderCom.Driver.HasRows) while (DreaderCom.Driver.Read())
                    {
                        for (int i = 0; i < DreaderCom.Driver.FieldCount; i++)
                        {
                            var CurRdrColumn = DreaderCom.Driver.GetValue(i);
                            this.Table[i, 0] = CurRdrColumn;
                        }
                    }
            }
            DreaderCom.SqlCmd.Connection.Close();
        }                           
    }
}


public struct customComConfgBulkCopyA
{
      public TransManSF.CommunicatorTypeS ComType;
      public customComConfgBulkCopyA(TransManSF.CommunicatorTypeS ctrComType = TransManSF.CommunicatorTypeS.SqlBcpyIDataReaderM)
      {
          this.ComType = ctrComType;
      }
}
public sealed class BulkCopyComSCL :CustomComA
{
     public new Configurations.comunicator.customComConfgBulkCopyA Meta;
     public SqlConnection Conn { get; set; }
     public Raw.SqlBcpyIDataReaderM ServerWriter { get; set; }
}

public class SqlDbTableM : SqlDB1stTransA
{
     virtual public DbSchema.Raw.TableDictionaryA TableDict { get; set; }
     public virtual new TransMan.Raw.Configurations.SDB1stTransConfgF.SDTOMetaA Meta { get; set; }
     virtual public Raw.ColumnSetsCollM Table { get; set; }
     public override TransMan.Raw.ComunicatorCLF.ComunicatorM propComunicator
     {
         get
         {
              return base.propComunicator;
         }
         set
         {
              base.propComunicator = value;
         }
     }
     public override TransMan.Raw.Executers.ExecuterM propExecuter
     {
         get
         {
             return base.propExecuter;
         }
         set
         {
             base.propExecuter = value;
         }
     }
     public SqlDbTableM(TransManSF.STDOTypeS ctrTransType)
            : base(TransManSF.DbIntreactorTypeS.TableObject) { }
}

public sealed class GetSDTOComSCL : CustomComA
{
    public new Configurations.comunicator.customComConfgGetSDTOReaderA Meta;
    public new IDbCommand SqlCmd;
    public Raw.GetSDTOIDataReaderM SDTOIDataReader { get; set; }
}

【问题讨论】:

  • propCommunicator.AsGetSDTOCom() 返回什么?这是一门你可以上手的课程吗?
  • @RePierre 是的,我肯定会在 5 分钟后添加更新
  • @RePierre 如果需要更多信息,我很乐意解释并分享,抱歉花了 25 分钟
  • 在您的更新中 AsGetSDTOCom() 仍然缺失。看起来它返回的是 SqlCommand 而不是 IDbCommand。你能展示那部分代码吗?
  • 看起来你的方法有点不对劲。除非您正在编写自己的数据库驱动程序,否则您不应该真正实现 IDataReader,这是您真正不想做的事情。您能否更具体地说明您要在这里实现的目标?

标签: c# sql-server performance downcast idatareader


【解决方案1】:

简短回答:您无法更改SqlCommand.ExecuteReader() 返回的类型。

它将始终是SqlDataReader 的一个实例。

各种解决方案:

1 在你觉得有意义的地方包装东西。

如果你走极端,请编写自己的 IDbProviderFactory,它用自己的连接、命令和数据读取器类包装 SqlConnection

例如,Miniprofiler 就是这样做的,用于检测所有 SQL 请求并收集执行时间、行数等。Source code

或者您可以使用某种扩展方法仅包装阅读器,例如:sqlCmd.ExecuteReader().AsMyReader()AsMyReader() 会做的是返回一个自定义的 IDataReader 来完成你的工作并委托给实际的 SqlDataReader

2 使用现有的帮助程序库

我不确定您在阅读内容时想要达到什么目的,但在这个领域存在很好的库。无需提出自己的解决方案。

FastMember (Nuget) 允许围绕任何IEnumerable&lt;T&gt;DataTable 创建IDataReader 接口。它易于用作SqlBulkCopy 的种子,以轻松插入最大数据。性能到 SQL Server 表中。

此外,为了简化 SQL 查询的执行和解析结果,Dapper 非常棒。

【讨论】:

  • 查看第一个链接自定义DbCommand 是解决方案核心的开始吗?如果我将其用作命令,它会使自定义IDataReader 的生活更轻松吗? public class ProfiledDbCommand : DbCommand, ICloneable
  • 不,一切的开始都是DbProviderFactory。它创建自己的DbConnection,后者创建自己的DbCommand,后者创建自己的DbDataReader
  • 好的,所以我会继续从源代码DbProviderFactory 进行调查,非常感谢!
  • 仍然坚持标准SqlDataReader,没有时间实施/测试最接近我意图的建议,例如IDbProviderFactory
猜你喜欢
  • 1970-01-01
  • 2012-12-17
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多