.NET DataTable пропускает строки в Load (DataReader)

Я пытаюсь заполнить 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);

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

 dt.Load(cmd.ExecuteReader());

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

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

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

Ответы

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

Не используйте

dr.Read()

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

Ответ 6

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

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

Например:

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

Странно....

Ответ 7

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

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

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

Ответ 8

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

        Dim deals As New DealsProvider()
        Dim adapter As New ReportingDataTableAdapters.ReportDealsAdapter
        Dim report As ReportingData.ReportDealsDataTable = deals.GetActiveDealsReport()
        rptReports.LocalReport.DataSources.Add(New ReportDataSource("ActiveDeals_Data", report))

Любопытно узнать, все ли это происходит.

Ответ 9

Вы пытались позвонить dt.AcceptChanges() после вызова dt.Load(cmd.ExecuteReader()), чтобы узнать, помогает ли это?

Ответ 10

В моем случае ни ORDER BY, ни dt.AcceptChanges() не работают. Я не знаю, для чего эта проблема. У меня есть 50 записей в базе данных, но в нем всего 49. пропуская первую строку, и если в datareader есть только одна запись, она ничего не показывает.

что за bizzareeee.....

Ответ 11

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

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

Итак, вместо

SELECT a
     , b
FROM table

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

SELECT a as gurgleurp
     , b
FROM table

и он работал.

Ответ 12

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

Ответ 13

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

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

    if(dataset.hasrows) - Missing row appears.