4

私は を持っていますSqlDataReaderが、決して に入りませんRead()

デバッグすると、 loop を通過します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プロファイラーでデバッグすると、データが表示されます....つまり、データが空ではないことを意味しますが、このループには入りません。

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'

できます。

4

3 に答える 3

3

これはあなたが求めている答えではないかもしれませんが、あなたのコード サンプルには、ADO.NET の貧弱な API 設計が原因で陥りやすい多くの不適切なコーディング プラクティスが示されています。この sql から .net への変換をすべて手動で行うのではなく、これを行うライブラリを使用する必要があります。

バグが発生しやすい API を使用していない場合は、バグを回避する方が簡単です。

PetaPocoをお勧めします。現在のコードよりも使いやすく、実質的にオーバーヘッドがありません (例を考えると、おそらく高速です)。ただし、他にも多くの代替手段があります。

コード サンプルの問題:

  • 不適切に破棄されたオブジェクト:適切に破棄SqlCommandしていません。接続も破棄していない可能性SqlDataReaderがあります(ただし、それは内部に依存します)。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
    });
}

そして、そのはるかに短く、読みやすく、より高速な形式で、うまくいけば、バグが何であれ、はるかに速く見つけることができます。

代替案:

  • ぺたぽこ
  • Dapper (機能は少ないですが、stackoverflow が使用しています!)
  • OrmLite (ServiceStack で有名)
  • 大規模(古い、dynamic悪い習慣を引き起こす可能性のある機能を使用します。自分が何をしているのかを本当に理解していない限り、これはお勧めしません)

エンティティ フレームワークや NHibernate のような、より重くて侵襲的な ORM を使用することもできますが、これらにはかなり多くの学習が必要であり、はるかに遅く、特定のワークフローを課すため、最良の選択にはならないと思います。あなたの場合。

于 2013-06-14T16:11:33.400 に答える
0

SQLプロファイラーでデバッグすると、データが表示されます....つまり、データが空ではないことを意味しますが、このループには入りません。

これは逆です。このループに入らない場合は、「データが空」、つまりクエリが行を返さないことを意味します。

バグはコードにあるのではなくSqlReader、パラメータに間違った値があるか、ファイルから読み取ったクエリが思ったものと異なる可能性があります。デバッガーを取り出して、クエリ テキストとパラメーターを調べます。

于 2013-06-14T16:09:23.417 に答える