Datareader пропускает первый результат

У меня есть довольно сложный SQL-запрос, который извлекает различные типы продуктов из базы данных на основе идентификатора клиента. Он извлекает три разных типа продуктов, идентифицируемых диапазонами их уникальных идентификаторов (например, идентификаторы 1000–1999 — это один тип продукта, 2000–2999 — другой, а 3000–3999 — еще один).

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 — это единственная часть пользовательского ввода, которая мне нужна, и когда я запускаю этот запрос к базе данных в SQL Server Management Studio Express, он работает нормально. Однако, когда я оборачиваю это в инструкцию using в веб-части, которую я пишу на C# для SharePoint, она не возвращает первую строку, которую должна, вместо этого возвращает нулевое значение. Например, если в SSMS я получаю три результата (скажем, «1001», «2008» и «3045»), то мой модуль чтения данных вернет только два результата с нулевым значением для первого (т. е. «null», «2008». "," и "3045"). Вот мой код на С#:

            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();

Наш профилировщик SQL показывает, что один и тот же запрос передается независимо от того, выполняется ли он через SSMS или из веб-части, за исключением того, что литерал используется вместо параметра. Кроме того, если я изменю параметр на литерал, у меня будет тот же результат. Есть ли несоответствие в том, как С# обрабатывает запросы SQL, а не в SSMS, или я как-то неправильно это реализовал?

Вот код для извлечения данных из считывателя в раскрывающийся список для полноты картины:

                    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;
                    }

Я полностью в тупике, и я очень ценю любую помощь, которую я могу получить.


person Geo Ego    schedule 19.01.2010    source источник
comment
Вы проверили, как выглядит ваш запрос в SQL Profiler?   -  person Oded    schedule 20.01.2010
comment
Запустите запрос, используя литерал «11» один раз, без параметров команды, что это вернет?   -  person Chris Haas    schedule 20.01.2010
comment
Вы проводите тестирование с идентификатором CustomerID 11 в своем коде?   -  person 37Stars    schedule 20.01.2010
comment
Я просмотрел запросы, выполняемые с обоих концов через наш профилировщик, и не увидел расхождений, кроме параметра и литерала. Я попытался изменить веб-часть, чтобы отправить идентификатор как литерал, а затем, назначив литерал параметру напрямую, и в обоих случаях, у меня возникла та же проблема. Я в тупике. Я был уверен, что к этому моменту у меня что-то выскочит.   -  person Geo Ego    schedule 20.01.2010


Ответы (3)


обновить

Оказалось, что проблема заключалась в дополнительном вызове dr.Read() перед циклом. Смотрите комментарии.

обновить

Глядя на код, кажется, что привязка данных находится не в том месте - может быть, что-то вроде этого? Кроме того, я изменил его, чтобы показать нулевые элементы... возможно, это обнажит логическую проблему.

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;

старый

Может быть, это что-то глупое вроде customers.SelectedValue.ToString().Trim()?

Вы можете запустить профилировщик и увидеть ТОЧНО SQL, который выполняет сервер... затем запустите его в SSMS, чтобы увидеть, получаете ли вы по-прежнему разные результаты.

person Hogan    schedule 19.01.2010
comment
Я не вижу ничего подобного, хотя я полагаю, что это не значит, что этого нет. При отладке я подключился к процессу SharePoint и прошел его, проверяя свои значения, и, похоже, он отлично передает параметр ID. - person Geo Ego; 20.01.2010
comment
Кроме того, я должен упомянуть, что я также пытался скопировать SQL-запрос, отправленный веб-частью из профилировщика, и вставить его в SSMS. У меня был тот же результат. - person Geo Ego; 20.01.2010
comment
Просто чтобы я понял, когда вы берете код, который вы видите в Profiler, и запускаете его в Enterprise Manager, вы получаете ожидаемые результаты? - person Hogan; 20.01.2010
comment
На самом деле у меня сейчас нет MS Profiler ... наше серверное программное обеспечение доступно только сетевым администраторам, поэтому я жду, чтобы поговорить с одним из них, чтобы получить его на моей машине. Тем не менее, я использовал профилировщик с открытым исходным кодом Arj Lab, чтобы получить результаты, о которых я упоминал ранее. Я собираюсь попробовать ваш код выше и посмотреть, смогу ли я найти некоторые ошибки в логике. Спасибо за вашу помощь! - person Geo Ego; 21.01.2010
comment
Хорошо. Похоже, что нули являются частью проблемы. Я заменил ваш код выше и выполнил несколько запросов к базе данных с помощью веб-части. Теперь я получаю несколько !NULL! значения, смешанные с моими результатами для клиентов, которые доставляют мне проблемы. Я работаю над логикой прямо сейчас, но я с радостью приму любой ваш вклад! - person Geo Ego; 21.01.2010
comment
как насчет изменения этого соединения, чтобы оно выглядело так: LEFT JOIN dbo.tblRotaryDieSpecs sm ON mids.fldMachine_ID = sm.fldMachine_ID поскольку таблица mids является таблицей машины, перейдите к источнику. - person Hogan; 21.01.2010
comment
Профилировщик MSSQL не является частью серверного программного обеспечения, вы можете запустить его с локального компьютера, и он должен быть доступен в SQL Server Management Studio -- в разделе Инструменты | Профилировщик SQL Server. Что такое открытый исходный код Arj Lab? Поиск в гугле не дал результатов. - person Hogan; 21.01.2010
comment
Извините, я хотел сказать, что наше программное обеспечение базы данных также является частью домена сетевого администратора. Инструмент Anj Lab находится здесь (видимо, я опечатался как Arj Lab): anjlab.com/en/ проекты/открытый исходный код/sqlprofiler. Причина, по которой я не могу изменить соединение таким образом, заключается в том, что для идентификации разных машин используются разные типы идентификаторов. Это странная модель данных, которая привела к уникальной схеме для правильной нормализации. На самом деле, вы очень помогли мне получить этот запрос: -логика. - person Geo Ego; 21.01.2010
comment
Я также попытался изменить SQL-запрос в соответствии с вашим заявлением. Он дает идентичные результаты. - person Geo Ego; 21.01.2010
comment
Извините, Гео, у меня закончились идеи — пока я не увижу некоторые образцы данных, я не могу придумать ничего, что могло бы помочь. Сокращение тестовых данных до наименьшего набора данных, который показывает проблему, может действительно помочь в отслеживании логической ошибки. Я думаю, что это может быть следующим шагом к поиску решения. - person Hogan; 21.01.2010
comment
Я тестировал это с конкретным номером клиента, который показывает проблему. Нет игральных костей. Я скопировал и вставил запрос непосредственно из профилировщика в SSMS и выполнил два запроса один за другим. Оба дали одинаковые (правильные) результаты. Есть ли способ просмотреть содержимое устройства чтения данных во время отладки? Я просмотрел его свойства и не вижу, где хранятся фактические данные. Я хотел бы посмотреть, правильно ли данные попадают к читателю и не исключает ли моя логика эти результаты. - person Geo Ego; 28.01.2010
comment
Хорошо. Просматривая еще раз несколько наборов данных, я понял, что упустил очень очевидное сходство: само устройство чтения данных всегда возвращает 'null' для первого результата. Я прошел через цикл, содержащий средство чтения данных, и каждый раз первый результат возвращает нулевое значение вместо первого значения, которое он должен видеть, а затем продолжает нормально работать с остальными значениями. Я не могу найти эту проблему в другом месте. Я могу немного изменить этот вопрос и опубликовать его повторно, так как проблема не в том, что я думал. - person Geo Ego; 28.01.2010
comment
Тогда проблема может заключаться в том, что запрос возвращает null для одной из строк? - person Hogan; 28.01.2010
comment
Нет. Запрос через SSMS возвращает правильное количество строк и делает то же самое, если я копирую и вставляю запрос из своей веб-части и запускаю его через SSMS. Пример: @CustomerID='8' SSMS: 1004, 1005, 3007, 2012 Веб-часть: 1005, 3007, 2012 @CustomerID='9' SSMS: 1015, 3019, 2061 Веб-часть: 3019, 2061 Я проверил это примерно десять раз. клиенты, и он постоянно делает одно и то же... запрос работает нормально, но средство чтения данных возвращает null вместо этого первого результата. Я сбит с толку. - person Geo Ego; 28.01.2010
comment
также попробуйте это: создайте списки items1 и items2, затем используйте items1.Add(flatName, itemValue); и items.Add(rotaryName, itemValue); - person Hogan; 28.01.2010
comment
Довольно много. Я вернулся к обработке нулей, которую я реализовал ранее, потому что с кодом, который вы разместили выше, он задыхается, когда достигает нуля, хотя это было здорово для их разоблачения. Однако я переместил привязку данных в конец оператора, как это было у вас. - person Geo Ego; 28.01.2010
comment
Я только что обновил код, который у меня есть. Я попробую другие ваши идеи и скоро свяжусь с вами. - person Geo Ego; 28.01.2010
comment
@Geo: попробуйте с привязкой данных вне цикла while. привязку данных следует использовать только один раз! - person Hogan; 28.01.2010
comment
Прости за это. Привязка данных находится вне цикла; Я скопировал его не туда, когда обновлял свой текущий код. Я пробовал отдельные списки; такие же результаты. Что бы я ни делал, этот считыватель данных постоянно пропускает первые результаты по сравнению с тем же запросом через SSMS. - person Geo Ego; 28.01.2010
comment
вы уверены, что перед циклом while нет dr.Read()? - person Hogan; 29.01.2010
comment
Ты ударил его по голове. У меня был ошибочный dr.Read() непосредственно перед циклом while. Вынул его и теперь все работает как по маслу. Извините за глупую ошибку, но большое спасибо, что нашли время, чтобы помочь мне с этим. Я собираюсь пойти дальше и отметить это как ответ, если вы хотите продолжить, и просто упомяну в ответе, что это dr.read() перед циклом while. Спасибо еще раз! - person Geo Ego; 29.01.2010

ваш пример кода показывает, что вы вызываете Read в DataReader дважды в начале, что приведет к тому, что читатель пропустит первую строку. Вам нужен только вызов чтения в цикле while.

  dr.read();  // unnecessary read call
  while (dr.Read())
  { }
person Venr    schedule 29.01.2010
comment
Дополнительное примечание: некоторое время код выглядел иначе, прежде чем он нашел проблему и добавил read() в пример кода. - person Hogan; 30.01.2010

Вы выполняете привязку данных внутри цикла чтения. На самом деле вы должны привязываться к перечисляемому после его заполнения.

Также обратите внимание на метод command.AddWithValue().

person cjk    schedule 28.01.2010
comment
AddWithValue(), вероятно, потерпит неудачу. Он хочет, чтобы числа представлялись в виде строк, AWV должен преобразовываться в числа. (Конечно, customerID должен быть представлен в БД как int, но это уже другая история...) - person Hogan; 28.01.2010
comment
Моя ошибка там. Хоган указал на это в первый раз, и я все исправил. Я просто скопировал этот фрагмент в неправильное место, когда обновлял свой код. Я посмотрел на AddWithValue, но да, я не вижу, чтобы он работал, поскольку все, с чем я имею дело, — это строки. - person Geo Ego; 28.01.2010