Reputation: 276
I have the following Webservice:
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()
});
}
}
}
}
I tested the SQL Statement in SQL Server Management Studio and it is working like a charm. But I am getting an error if I invoke the method in the browser:
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
What am I doing wrong?
Upvotes: 7
Views: 36277
Reputation: 4001
The data reader doesn't know what r.NAME is because the columns that are actually returned are NAME and NAME. You can use aliases to differentiate the two, like this:
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
And then access the returned data by the alias:
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()
});
}
Upvotes: 0
Reputation: 20320
It doesn't like the alias r, which of course gives you a potential problem as your column names are not unique.
Try something like:
Select r.Name as RName, s.Name as SName
...
Then rdr["RName"]
and rdr["SName"]
will be goers.
Upvotes: 1
Reputation: 73554
When r.Name is selected into the DataReader, it reads only the field name - Name. When selecting the fields, it doesn't include the table specifiers (r. and s.)
It can't find "r.Name" or "s.Name" because when evaluating, the reader is simply returning two columns, both just named "Name" So when searching for r.Name, the runtime is saying that "r.Name is not in the list of valid column names" (which is manifested in an IndexOutOfRange exception).
If you want to be able to access it by name, you have to use the AS statement to give the resulting in-memory results of the query distinct field names:
I think I'm stating that badly, but in essence, your code should be modified as such:
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()
});
}
}
}
}
Upvotes: 12
Reputation: 54877
Table names cannot be used to qualify the field names in a SqlDataReader
; the field name, in your case, is "NAME"
.
To avoid the naming conflict, you should rename the columns in your projection:
SELECT r.NAME AS RegionName, s.NAME AS StateName FROM REGION r …
Then, access the fields using the new names:
if (rdr["RegionName"] != DBNull.Value && rdr["StateName"] != DBNull.Value)
Upvotes: 0