【问题标题】:SqlDataReader does not work - does not read dataSqlDataReader 不起作用 - 不读取数据
【发布时间】:2013-06-14 16:03:10
【问题描述】:

我有一个SqlDataReader,但它从未进入Read()

当我调试它时,它通过循环while(readerOne.Read())。即使有数据,它也不会进入这个循环。

public static List<Pers_Synthese> Get_ListeSynthese_all(string codeClient, DateTime DateDeb, DateTime DateFin)
{
   try
   {
      using (var connectionWrapper = new Connexion())
      {
         var connectedConnection = connectionWrapper.GetConnected();

         string sql_Syntax = Outils.LoadFileToString(Path.Combine(appDir, @"SQL\Get_ListeSynthese_All.sql"));

         SqlCommand comm_Command = new SqlCommand(sql_Syntax, connectionWrapper.conn);
         comm_Command.Parameters.AddWithValue("@codeClioent", codeClient);
         comm_Command.Parameters.AddWithValue("@DateDeb", DateDeb);
         comm_Command.Parameters.AddWithValue("@DateFin", DateFin);

         List<Pers_Synthese> oListSynthese = new List<Pers_Synthese>();

         SqlDataReader readerOne = comm_Command.ExecuteReader();

         while (readerOne.Read())
         {
            Pers_Synthese oSyntehse = new Pers_Synthese();
            oSyntehse.CodeTrf = readerOne["CODE_TARIF"].ToString();
            oSyntehse.NoLV = readerOne["NOID"].ToString();
            oSyntehse.PrxUnitaire = readerOne["PRIX_UNITAIRE"].ToString();
            oSyntehse.ZoneId = readerOne["LE_ZONE"].ToString();
            oSyntehse.LeZone = readerOne["LIB_ZONE"].ToString();
            oSyntehse.LeDept = readerOne["DEPT"].ToString();
            oSyntehse.LeUnite = readerOne["ENLEV_UNITE"].ToString();
            oSyntehse.LePoids = Convert.ToInt32(readerOne["POID"]);
            //oSyntehse.LePoidsCorr = Convert.ToInt32(readerOne["POID_CORR"]);
            oSyntehse.LeColis = readerOne["NBR_COLIS"].ToString();
            oSyntehse.LeCr = readerOne["NBR_CREMB"].ToString();
            oSyntehse.SumMontantCR = readerOne["ENLEV_CREMB"].ToString();
            oSyntehse.LeVd = readerOne["NBR_DECL"].ToString();
            oSyntehse.SumMontantVD = readerOne["ENLEV_DECL"].ToString();
            oSyntehse.LePrixHT = readerOne["PRIX_HT"].ToString();
            oSyntehse.LePrixTTC = readerOne["PRIX_TTC"].ToString();
            oSyntehse.TrDeb = readerOne["TR_DEB"].ToString();
            oSyntehse.TrFin = readerOne["TR_FIN"].ToString();

            oListSynthese.Add(oSyntehse);
         }
         readerOne.Close();
         readerOne.Dispose();
         return oListSynthese;
      }
  }
  catch (Exception excThrown)
  {
     throw new Exception(excThrown.Message);
  }
}

当我使用 SQL Server profiler 调试它时,它会显示数据......这意味着数据不是空的,但它永远不会进入这个循环。

while (readerOne.Read())
{

顺便说一下我的连接类:

 class Connexion : IDisposable 
    {
        public SqlConnection conn;
        public SqlConnection GetConnected()
        {
            try
            {
                string strConnectionString = Properties.Settings.Default.Soft8Exp_ClientConnStr;
                conn = new SqlConnection(strConnectionString);
            }
            catch (Exception excThrown)
            {
                conn = null;
                throw new Exception(excThrown.InnerException.Message, excThrown);
            }

            // Ouverture et restitution de la connexion en cours
            if (conn.State == ConnectionState.Closed) conn.Open();
            return conn;
        }

        public Boolean IsConnected
        {
            get { return (conn != null) && (conn.State != ConnectionState.Closed) && (conn.State != ConnectionState.Broken); }
        }

        public void CloseConnection()
        {
            // Libération de la connexion si elle existe
            if (IsConnected)
            {
                conn.Close();
                conn = null;

            }

        }

        public void Dispose()
        {
            CloseConnection();
        }
    }

还有我的 SQL 语句:

exec sp_executesql N'SELECT CODE_TARIF,PRIX_UNITAIRE,TR_DEB,TR_FIN,LE_ZONE,T_TARIF_ZONE.LIBELLE as LIB_ZONE,
  SUBSTRING(CP_DEST,1,2) as DEPT,T_UNITE.LIBELLE as ENLEV_UNITE,
  count(NOID)as NOID,
   SUM(CASE WHEN POID_CORR IS NOT NULL THEN POID_CORR ELSE POID END) as POID,sum(NBR_COLIS)as NBR_COLIS,COUNT(NULLIF(ENLEV_CREMB,0))as NBR_CREMB, sum(ENLEV_CREMB)as ENLEV_CREMB,COUNT(NULLIF(ENLEV_DECL,0))as NBR_DECL,sum(ENLEV_DECL)as ENLEV_DECL,sum(PRIX_HT)as PRIX_HT,sum(PRIX_TTC)as PRIX_TTC, sum (POID_CORR)as POID_CORR
  FROM LETTRE_VOIT_FINAL
   LEFT JOIN T_TARIF_ZONE ON LETTRE_VOIT_FINAL.LE_ZONE = T_TARIF_ZONE.NO_ID
  LEFT JOIN T_UNITE ON LETTRE_VOIT_FINAL.ENLEV_UNITE = T_UNITE.NO_ID
  where code_client = @codeClioent
   and DATE_CLOTUR_REEL BETWEEN @DateDeb AND @DateFin
   and STATUT_LV = 2

 group by CODE_TARIF,PRIX_UNITAIRE,TR_DEB,TR_FIN,LE_ZONE,T_TARIF_ZONE.LIBELLE,SUBSTRING(CP_DEST,1,2),T_UNITE.LIBELLE
 order by LE_ZONE,PRIX_UNITAIRE

',N'@codeClioent nvarchar(8),@DateDeb datetime,@DateFin datetime',@codeClioent=N'17501613',@DateDeb='2013-06-05 00:00:00',@DateFin='2013-06-05 23:59:00'

它返回 SQL 分析器上的数据:

我的真实查询:

SELECT CODE_TARIF,PRIX_UNITAIRE,TR_DEB,TR_FIN,LE_ZONE,T_TARIF_ZONE.LIBELLE as LIB_ZONE,
  SUBSTRING(CP_DEST,1,2) as DEPT,T_UNITE.LIBELLE as ENLEV_UNITE,
  count(NOID)as NOID,
   SUM(CASE WHEN POID_CORR IS NOT NULL THEN POID_CORR ELSE POID END) as POID,sum(NBR_COLIS)as NBR_COLIS,COUNT(NULLIF(ENLEV_CREMB,0))as NBR_CREMB, sum(ENLEV_CREMB)as ENLEV_CREMB,COUNT(NULLIF(ENLEV_DECL,0))as NBR_DECL,sum(ENLEV_DECL)as ENLEV_DECL,sum(PRIX_HT)as PRIX_HT,sum(PRIX_TTC)as PRIX_TTC, sum (POID_CORR)as POID_CORR
  FROM LETTRE_VOIT_FINAL
   LEFT JOIN T_TARIF_ZONE ON LETTRE_VOIT_FINAL.LE_ZONE = T_TARIF_ZONE.NO_ID
  LEFT JOIN T_UNITE ON LETTRE_VOIT_FINAL.ENLEV_UNITE = T_UNITE.NO_ID
  where code_client = @codeClioent
   and DATE_CLOTUR_REEL BETWEEN @DateDeb AND @DateFin
   and STATUT_LV = 2

 group by 

    CODE_TARIF,PRIX_UNITAIRE,TR_DEB,TR_FIN,LE_ZONE,T_TARIF_ZONE.LIBELLE,SUBSTRING(CP_DEST,1,2),T_UNITE.LIBELLE
     order by LE_ZONE,PRIX_UNITAIRE

很奇怪....当数据介于:

DATE_CLOTUR_REEL BETWEEN '2013-06-05 00:00:00' and '2013-06-05 23:59:00'

但是

DATE_CLOTUR_REEL BETWEEN '2013-06-01 00:00:00' and '2013-06-05 23:59:00'

它有效。

【问题讨论】:

  • 您的 SQL 文本是否仅包含一个 SELECT 语句?如果不止一个,那么您可以通过调用reader.NextResult() 来浏览它们。
  • 使用像 Entity Framework、Dapper.NET 或 NHibberate 这样的体面的 ORM 会让这简单得多.... 不麻烦@987654334 @,没有凌乱的“胶水代码”.....
  • 能不能把SQL语句贴一下(调试时sql_Syntax的内容)。
  • 您发布了您在分析器中看到的内容。您可以在.NET 端发布sql_Syntax 变量的内容吗?我的猜测是那里有多个语句或命令 - 这将导致探查器中有多个语句,因此即使您所需的查询正常工作,其中的其他内容也会影响您的结果。
  • Joe Enos 所说的 - 向我们展示真正的查询...

标签: c# sql-server sqldatareader


【解决方案1】:

这是应该的方式。你没有做connection.Open() 还要设置连接字符串。

   private static void ReadOrderData(string connectionString)
    {
        string queryString =
            "SELECT OrderID, CustomerID FROM dbo.Orders;";

        using (SqlConnection connection =
                   new SqlConnection(connectionString))
        {
            SqlCommand command =
                new SqlCommand(queryString, connection);
            connection.Open();

            SqlDataReader reader = command.ExecuteReader();

            // Call Read before accessing data. 
            while (reader.Read())
            {
                ReadSingleRow((IDataRecord)reader);
            }

            // Call Close when done reading.
            reader.Close();
        }
 }

如何做到的完美例子属于MSDN - Microsoft Website

注意:

        SqlCommand command =
            new SqlCommand(queryString, connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();
  1. 创建SqlCommand
  2. 然后打开连接

你用另一种方式做,你打开它然后创建命令。

我也没有看到你在哪里设置了查询字符串,我只是看到你添加了参数;你错过了吗?

【讨论】:

  • 当你这样做的时候 - 也请把 SqlCommandSqlDataReader 放到 using()...... 块中!
  • 我假设连接字符串被应用并且连接被包装类打开。否则他们会得到一个异常,而不仅仅是没有行。
  • 查询被设置在SqlCommand comm_Command = new SqlCommand(sql_Syntax, connectionWrapper.conn); - sql_Syntax 字符串是查询,connectionWrapper.connSqlConnection
  • sql_Syntax 不存在,SqlConnection 在那之前打开了!
【解决方案2】:

这可能不是您要寻找的答案,但您的代码示例展示了许多由于 ADO.NET 糟糕的 API 设计而很容易陷入的不良编码实践。与其手动完成所有这些 sql 到 .net 的转换,不如使用一个库来为您完成这些。

不使用容易出错的 API 时更容易避免错误。

我推荐 PetaPoco - 它比您当前的代码更易于使用,并且几乎没有开销(并且根据您的示例,它可能更快)。但是,还有许多其他选择。

您的代码示例存在问题:

  • 不当处置对象:您没有正确处置SqlCommandSqlDataReader。您可能也没有处理连接(但这取决于Connexion 内部)。
  • 使用.ToString 而不是类型安全的强制转换。您应该永远从 SqlDataReader 中提取数据,因为它破坏了类型系统的全部意义,而且启动速度很慢。 (PetaPoco 或类似的东西在这里会有很大帮助)
  • 由于(无意义的)try-catch 错误,您将丢弃堆栈跟踪。这只会使您的代码可读性降低,并且更难调试。除非有,否则不要抓。
  • 让您的查询远离代码 - 您的代码与查询紧密耦合,这种分离只会使它们难以保持同步。此外,每次查询时从文件系统加载都很慢,并且会打开不必要的文件系统相关故障模式,例如锁定、最大路径长度和权限。 这可能是您的错误的根源 - 您的查询可能没有按照您的想法执行。

使用 PetaPoco 或类似的东西,你的整个函数看起来像这样:

public static List<Pers_Synthese> Get_ListeSynthese_all(
                string codeClient, DateTime DateDeb, DateTime DateFin) {
    var db = new PetaPoco.Database("Soft8Exp_ClientConnStr");

    //you should probably not be storing a query in a file.
    //To be clear: your query should not be wrapped in exec sp_executesql,
    //ADO.NET will do that for you.
    string sql_Syntax = Outils.LoadFileToString(
        Path.Combine(appDir, @"SQL\Get_ListeSynthese_All.sql"));

    //You'll need to rename Pers_Synthese's properties to match the db,
    // or vice versa, or you can annotate the properties with the column names.
    return db.Fetch<Pers_Synthese>(sql_Syntax, new {
        codeClioent = codeClient, //I suspect this is a typo
        DateDeb,
        DateFin
    });
}

在更短、更易读、更快速的形式中,您有望更快地找到任何错误。

替代方案:

  • PetaPoco
  • Dapper(功能较少,但 stackoverflow 使用它!)
  • OrmLite(ServiceStack 名声)
  • Massive(年龄较大,使用dynamic,这是一个可能导致不良习惯的功能 - 除非您真的知道自己在做什么,否则我不建议这样做)

您可以使用更重、更具侵入性的 ORM,例如 Entity 框架和 NHibernate,但这些需要更多的学习,而且速度要慢得多,并且它们会强加特定的工作流程,我认为这不会使它们适合您情况的最佳选择。

【讨论】:

    【解决方案3】:

    当我使用 sql profiler 调试它时,它会显示数据......这意味着数据不是空的,但它永远不会进入这个循环。

    反之亦然:如果它从未进入此循环,则表示“数据为空”,即查询不返回任何行。

    错误在您的代码中,而不是SqlReader:您的参数中可能有错误的值,或者您从文件中读取的查询不是您认为的那样。取出调试器并检查查询文本和参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多