.NET DataTable пропускает строки при загрузке (DataReader) - PullRequest
19 голосов
/ 23 октября 2008

Я пытаюсь заполнить DataTable, построить LocalReport, используя следующее:

MySqlCommand cmd = new MySqlCommand();
cmd.Connection = new MySqlConnection(Properties.Settings.Default.dbConnectionString);
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT ... LEFT JOIN ... WHERE ..."; /* query snipped */

// prepare data
dataTable.Clear();
cn.Open();
// fill datatable
dt.Load(cmd.ExecuteReader());
// fill report
rds = new ReportDataSource("InvoicesDataSet_InvoiceTable",dt);
reportViewerLocal.LocalReport.DataSources.Clear();
reportViewerLocal.LocalReport.DataSources.Add(rds);

В какой-то момент я заметил, что отчет был неполным, и в нем отсутствовала одна запись. Я изменил несколько условий, чтобы запрос возвращал ровно две строки и ... сюрприз : отчет показывает только одну строку вместо двух. Я попытался отладить его, чтобы найти, где проблема, и я застрял на

 dt.Load(cmd.ExecuteReader());

Когда я заметил, что DataReader содержит две записи, а DataTable содержит только одну. Случайно я добавил в запрос предложение ORDER BY и заметил, что на этот раз отчет показывался правильно.

Очевидно, DataReader содержит две строки, но DataTable читает обе из них, только если строка SQL-запроса содержит ORDER BY (в противном случае она читает только последнюю). Кто-нибудь может объяснить, почему это происходит и как это можно исправить?

Edit: Когда я впервые опубликовал вопрос, я сказал, что он пропускает первый ряд; позже я понял, что он на самом деле только прочитал последнюю строку, и я соответственно отредактировал текст (в то время все записи были сгруппированы в две строки, и казалось, что первая пропускается, когда фактически отображается только последняя). Это может быть вызвано тем, что у него не было уникального идентификатора, по которому можно было бы различать строки, возвращаемые MySQL, поэтому добавление оператора ORDER BY заставило его создать уникальный идентификатор для каждой строки.
Это всего лишь теория, и мне нечего ее поддержать, но все мои тесты, похоже, дают один и тот же результат.

Ответы [ 13 ]

7 голосов
/ 09 февраля 2012

вопросу несколько лет, но я не нашел достойного ответа, кроме вышеупомянутого обходного пути.

Немного покопавшись, я обнаружил, что метод DataTable.Load ожидает столбец первичного ключа в базовых данных. Если вы внимательно прочитаете документацию, это станет очевидным, хотя это не указано явно.

Если у вас есть столбец с именем "id", он, кажется, использует его (что исправило его для меня). В противном случае он просто использует первый столбец, независимо от того, является он уникальным или нет, и перезаписывает строки с тем же значением в этом столбце, что и при чтении. Если у вас нет столбца с именем «id», а ваш первый столбец не уникален, я бы посоветовал попытаться установить столбцы первичного ключа в datatable явно перед загрузкой устройства чтения данных.

6 голосов
/ 09 января 2011

На всякий случай, если у кого-то возникла проблема, подобная раку, я использовал If DataReader.Read ... вместо If DataReader.HasRows для проверки существования перед вызовом dt.load(DataReader) Doh!

4 голосов
/ 15 апреля 2014

Сегодня сталкивался с этой проблемой.

Ничто в этой теме, к сожалению, не исправило, но потом я завернул свой SQL-запрос в другой оператор SELECT, и он заработал!

Например:

SELECT * FROM (
    SELECT ..... < YOUR NORMAL SQL STATEMENT HERE />
) allrecords

Странно ....

4 голосов
/ 29 февраля 2012

Была такая же проблема. Это потому, что первичный ключ во всех строках одинаков. Вероятно, это то, что используется для ввода результатов, и поэтому просто перезаписывает одну и ту же строку снова и снова.

Datatables.Load указывает на метод fill, чтобы понять, как он работает. На этой странице указано, что это первичный ключ. Поскольку первичные ключи могут встречаться только один раз и используются в качестве ключей для строки ...

"Затем операция Fill добавляет строки к целевым объектам DataTable в DataSet, создавая объекты DataTable, если они еще не существуют. При создании объектов DataTable операция Fill обычно создает только метаданные имени столбца. Однако, если MissingSchemaAction свойство установлено в AddWithKey, также создаются соответствующие первичные ключи и ограничения. " (http://msdn.microsoft.com/en-us/library/zxkb3c3d.aspx)

3 голосов
/ 09 декабря 2013

Не использовать

dr.Read()

Потому что он перемещает указатель на следующую строку. Удалите эту строку, надеюсь, она будет работать.

2 голосов
/ 17 января 2009

У меня была такая же проблема. Я взял подсказку из вашего блога и включил в запрос предложение ORDER BY, чтобы они могли сформировать уникальный ключ для всех записей, возвращаемых запросом. Это решило проблему. Какая-то странная.

1 голос
/ 28 апреля 2016

Я знаю, что это старый вопрос, но для меня мысль, которая работала, когда при запросе базы данных доступа и обращении к ней отсутствовала 1 строка в запросе, заключалась в изменении следующего: -

    if(dataset.read())  - Misses a row.

    if(dataset.hasrows) - Missing row appears.
1 голос
/ 23 октября 2008

Можете ли вы получить реальный запрос, который запускается из профилировщика SQL, и попробовать запустить его? Это может быть не то, что вы ожидали.

Получаете ли вы тот же результат при использовании SqlDataAdapter.Fill (dataTable)?

Пробовали ли вы другое командное поведение на ридере? Документы MSDN

0 голосов
/ 09 октября 2014

У меня была такая же проблема .. вообще не использовал dataReader.Read () .. он будет указатель на следующую строку. Вместо этого используйте напрямую datatable.load (dataReader).

0 голосов
/ 26 марта 2014

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

В моем случае использование псевдонима для столбца, используемого в качестве PrimaryKey, решило проблему.

Итак, вместо

SELECT a
     , b
FROM table

Я использовал

SELECT a as gurgleurp
     , b
FROM table

и это сработало.

...