-1

以下を含む DataTable dt があります。ここに画像の説明を入力

ご覧のとおり、ここには 2 つのファイル セットがあります。ベースライン (列 1 ~ 3) とターゲット (列 4 ~ 6) です。この場合、4 つのベースライン ファイル m4、m5、m1、および m3 (行 5 の m1 は行 3 からコピーされます) と 1 つのターゲット ファイル m1 があります。問題は、ベースライン ファイル m1.txt の情報が重複しているため、次の LINQ ステートメントを使用して削除しようとしています。

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"] == baselineSubfolder
        && row["BASELINE_FILE"] == baselineFilename
        && row["BASELINE_CHECKSUM"] == baselineChecksum
        && row["STATUS"] == "remove"
    ).ToArray();

foreach (DataRow dr in extraneousRows)
    {
        dt.Rows.Remove(dr);
    }

これにより、DataTable から 3 行目が削除されますが、そうではありません。行を省略してもコードは && row["STATUS"] == "remove"正常に機能するので、機能していることがわかります。また、baselineSubfolder、baselineFilename、baselineChecksum の値は正しいため、問題はありません。

しかし、何らかの理由で、ステータス列に関する行を含めると、DataSet ビジュアライザー (上の写真) によると明らかであるにもかかわらず、その行が DataTable にあることが検出されません。そのため、foreach ループに入ったり、必要なファイルを削除したりすることはありません。どうして???

ベースライン ファイルの情報 (最初の 4 行) はデータベースから取得されますが、ターゲット ファイルのフィールドはユーザーの入力に従って生成されます。ただし、DataTable を直接クエリしているので、情報がどこから来ているかがどのように問題になるかはわかりません...

アップデート

OK、ばかげたジェイミー・キーリングの提案に従った後、問題は foreach ループに関係していると判断しました。このクエリは単一の行のみを返す必要があるため、ループを完全に排除しました。私の修正されたコードは次のようになります。

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"] == baselineSubfolder
        && row["BASELINE_FILE"] == baselineFilename
        && row["BASELINE_CHECKSUM"] == baselineChecksum
        && row["STATUS"] == "remove"
    ).SingleOrDefault();

dt.Rows.Remove(extraneousRows);

何らかの理由で extraneousRows は null のままで、最後の行で実行時エラーが発生しています。IndexOutOfRangeException: The given DataRow is not in the current DataRowCollection

なぜこれが機能しないのですか?

4

1 に答える 1

0

実際には、列の値を文字列にキャストする必要があったことが問題であることがわかりました。ソリューションは信じられないほど簡単でした: 列名とビオラの後に .ToString() を追加するだけです! 次のコードは魅力的に機能しました。

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"].ToString() == baselineSubfolder
        && row["BASELINE_FILE"].ToString() == baselineFilename
        && row["BASELINE_CHECKSUM"].ToString() == baselineChecksum
        && row["STATUS"].ToString() == "remove"
    ).SingleOrDefault();

dt.Rows.Remove(extraneousRows);

また、DataTable のすべての行を反復処理することにより、LINQ 以外の方法でこれを行う方法も見つけました。最も効率的ではありませんが、機能します。

for (int z = 0; z < dt.Rows.Count; z++)
{
    if ((dt.Rows[z]["BASELINE_FOLDER"].ToString() == baselineSubfolder)
        && (dt.Rows[z]["BASELINE_FILE"].ToString() == baselineFilename)
        && (dt.Rows[z]["BASELINE_CHECKSUM"].ToString() == baselineChecksum)
        && (dt.Rows[z]["STATUS"].ToString() == "remove"))
    {
        dt.Rows[z].Delete();
    }
}
dt.AcceptChanges();
于 2013-03-21T19:16:31.300 に答える