6

次の Web サービスがあります。

using (SqlCommand cmd = new SqlCommand(@"SELECT r.NAME, s.NAME FROM REGION r LEFT OUTER JOIN STADT s ON s.REGION_ID = r.ID ORDER BY r.NAME", con))
{
    con.Open();
    using (SqlDataReader rdr = cmd.ExecuteReader())
    {
        while (rdr.Read())
        {
            if (rdr["r.NAME"] != DBNull.Value && rdr["s.NAME"] != DBNull.Value)
            {
                stadtObject.Add(new STADT()
                {
                    RegionName = rdr["r.NAME"].ToString(),
                    StadtName = rdr["s.NAME"].ToString()
                });
            }
        }
    }
}

SQL Server Management Studioで SQL ステートメントをテストしましたが、うまく機能しています。しかし、ブラウザーでメソッドを呼び出すと、エラーが発生します。

System.IndexOutOfRangeException: r.NAME
   at System.Data.ProviderBase.FieldNameLookup.GetOrdinal(String fieldName)
   at System.Data.SqlClient.SqlDataReader.GetOrdinal(String name)
   at System.Data.SqlClient.SqlDataReader.get_Item(String name)
   at StadtHelper.Stadt() in C:\Users\Yeah\Documents\Visual Studio 2010\Projects\WebService1\WebService1\StadtHelper.cs:line 31
   at WebService1.Service1.Stadt() in C:\Depp\Ushi\Documents\Visual Studio 2010\Projects\WebService1\WebService1\Service1.asmx.cs:line 77

私は何を間違っていますか?

4

4 に答える 4

10

r.Name が DataReader に選択されると、フィールド名 - Name のみが読み取られます。フィールドを選択するとき、テーブル指定子 (r. および s.) は含まれません。

"r.Name" または "s.Name" を見つけることができません。これは、評価時にリーダーが単純に 2 つの列を返し、両方とも "Name" という名前になっているためです。したがって、r.Name を検索すると、ランタイムは "r. Name is not in the list of valid column names" (これは IndexOutOfRange 例外で明らかになります)。

名前でアクセスできるようにする場合は、AS ステートメントを使用して、クエリの個別のフィールド名のメモリ内結果を取得する必要があります。

私はそれをひどく述べていると思いますが、本質的に、コードは次のように変更する必要があります。

using (SqlCommand cmd = new SqlCommand(@"SELECT r.NAME AS rName, s.NAME AS sName FROM REGION r LEFT OUTER JOIN STADT s ON s.REGION_ID = r.ID ORDER BY r.NAME", con))
{
    con.Open();
    using (SqlDataReader rdr = cmd.ExecuteReader())
    {
        while (rdr.Read())
        {
            if (rdr["rNAME"] != DBNull.Value && rdr["sNAME"] != DBNull.Value)
            {
                stadtObject.Add(new STADT()
                {
                    RegionName = rdr["rNAME"].ToString(),
                    StadtName = rdr["sNAME"].ToString()
                });
            }
        }
    }
}
于 2012-06-07T21:19:28.230 に答える
1

エイリアス r は好きではありません。もちろん、列名が一意ではないため、潜在的な問題が発生します。

次のようなものを試してください:

Select r.Name as RName, s.Name as SName...

その後rdr["RName"]rdr["SName"]常連になります。

于 2012-06-07T21:23:22.757 に答える
0

のフィールド名を修飾するためにテーブル名を使用することはできませんSqlDataReader。あなたの場合、フィールド名はです"NAME"

名前の競合を避けるために、プロジェクションの列の名前を変更する必要があります。

SELECT r.NAME AS RegionName, s.NAME AS StateName FROM REGION r …

次に、新しい名前を使用してフィールドにアクセスします。

if (rdr["RegionName"] != DBNull.Value && rdr["StateName"] != DBNull.Value)
于 2012-06-07T21:21:31.110 に答える
0

実際に返される列は NAME と NAME であるため、データ リーダーは r.NAME が何であるかを知りません。次のように、エイリアスを使用して 2 つを区別できます。

SELECT r.NAME as REGION_NAME, s.NAME as STADT_NAME FROM REGION r LEFT OUTER JOIN STADT s ON s.REGION_ID = r.ID ORDER BY r.NAME

次に、返されたデータにエイリアスでアクセスします。

if (rdr["REGION_NAME"] != DBNull.Value && rdr["STADT_NAME"] != DBNull.Value)
                    {
                        stadtObject.Add(new STADT()
                        {
                            RegionName = rdr["REGION_NAME"].ToString(),
                            StadtName = rdr["STADT_NAME"].ToString()
                        });
                    }
于 2012-06-07T21:25:20.100 に答える