问题
I have a fairly complex SQL query that pulls different types of products from a database based on a customer ID. It pulls three different types of products, identified by their unique identifier number ranges (i.e., IDs 1000-1999 are one type of product, 2000-2999 are another, and 3000-3999 are yet another).
SELECT b.fldMachineName, m2.fldRotaryPressName, mids.fldMachine_ID
FROM dbo.tblCustomerGeneralInfo c
LEFT JOIN dbo.tblMachine_IDs mids ON c.fldCustomer_ID = mids.fldCustomer_ID
LEFT JOIN dbo.tblBobstFlatDieSpecs b ON mids.fldMachine_ID = b.fldMachine_ID
LEFT JOIN dbo.tblDieInfo m1 ON mids.fldMachine_ID = m1.fldMachine_ID
LEFT JOIN dbo.tblRotaryDieSpecs sm ON m1.fldMachine_ID = sm.fldMachine_ID
LEFT JOIN dbo.tblRotaryPresses m2 ON sm.fldRotaryPress_ID = m2.fldRotaryPress_ID
WHERE c.fldCustomer_ID = '20'
ORDER BY fldRotaryPressName
c.fldCustomer_ID is the only piece of user input that I need, and when I run this query against the database in SQL Server Management Studio Express, it runs fine. However, when I wrap this in a using statement in the web part I am writing in C# for SharePoint, it does not return the first row that it should, instead returning a null value. For instance, if in SSMS I get three results (say, '1001,' '2008,' and 3045') then my datareader will return only two results, with a null value for the first (i.e., 'null,' '2008,' and '3045'). Here is my code in C#:
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT b.fldMachineName, m2.fldRotaryPressName, mids.fldMachine_ID " +
"FROM dbo.tblCustomerGeneralInfo c " +
"LEFT JOIN dbo.tblMachine_IDs mids ON c.fldCustomer_ID = mids.fldCustomer_ID " +
"LEFT JOIN dbo.tblBobstFlatDieSpecs b ON mids.fldMachine_ID = b.fldMachine_ID " +
"LEFT JOIN dbo.tblDieInfo m1 ON mids.fldMachine_ID = m1.fldMachine_ID " +
"LEFT JOIN dbo.tblRotaryDieSpecs sm ON m1.fldMachine_ID = sm.fldMachine_ID " +
"LEFT JOIN dbo.tblRotaryPresses m2 ON sm.fldRotaryPress_ID = m2.fldRotaryPress_ID " +
"WHERE c.fldCustomer_ID = @CustomerID " +
"ORDER BY fldRotaryPressName", con))
{
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 4).Value = customers.SelectedValue.ToString();
Our SQL profiler shows the same query being passed regardless of if it's done through SSMS or from the web part, except for the literal being used versus the parameter. Also, if I change the parameter to a literal, I have the same result. Is there a discrepancy in the way that C# handles SQL queries as opposed to SSMS, or have I somehow implemented it incorrectly?
Here is the code for pulling the data from the reader into the dropdownlist, for the sake of completeness:
dr.read();
while (dr.Read())
{
try
{
string itemValue = Convert.ToString(dr["fldMachine_ID"]);
string flatName = Convert.ToString(dr["fldMachineName"]);
if (!string.IsNullOrEmpty(flatName))
{
items.Add(flatName, itemValue);
}
string rotaryName = Convert.ToString(dr["fldRotaryPressName"]);
if (!string.IsNullOrEmpty(rotaryName))
{
items.Add(rotaryName, itemValue);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// Bind list to ddl.
machines.DataSource = items;
machines.DataValueField = "Value";
machines.DataTextField = "Key";
machines.DataBind();
machines.Enabled = true;
}
I am completely stumped, and I really appreciate any help I can get.
回答1:
update
Turned out the problem was a extra dr.Read() call before the loop. See comments.
update
Looking at the code, it seems the databind is in the wrong place -- maybe something like this? Also, I changed it to show the null items... maybe this will expose a logic problem.
while (dr.Read())
{
try
{
string itemValue = dr["fldMachine_ID"].ToString();
string flatName = dr["fldMachineName"].ToString();
if (string.IsNullOrEmpty(flatName)) flatName = "!NULL!";
if (string.IsNullOrEmpty(itemValue)) itemValue = "!NULL!";
items.Add(flatName, itemValue);
string rotaryName = dr["fldRotaryPressName"].ToString();
if (string.IsNullOrEmpty(rotaryName)) rotaryName= "!NULL!";
items.Add(rotaryName, itemValue);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// Bind list to ddl.
machines.DataSource = items;
machines.DataValueField = "Value";
machines.DataTextField = "Key";
machines.DataBind();
machines.Enabled = true;
old
Could it be something silly like customers.SelectedValue.ToString().Trim()
?
You can run the profiler and see EXACTLY the SQL that the server is executing... then run that in SSMS to see if you still get different results.
回答2:
your code sample shows you calling Read on the DataReader twice at the start, that would cause the reader to skip the first row. You should only need the read call in the while loop.
dr.read(); // unnecessary read call
while (dr.Read())
{ }
回答3:
You are doing the databind inside the read loop. Really you should bind to an enumerable after it has been populated.
Also, look at the command.AddWithValue()
method.
来源:https://stackoverflow.com/questions/2097071/datareader-skips-first-result