Метод обновления SQLiteDataAdapter возвращает 0

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

Программа выводит:

Num rows loaded is 83
Num rows updated is 0

Исходный код:

public void InsertData(String csvFileName, String tableName)
{
    String dir = Path.GetDirectoryName(csvFileName);
    String name = Path.GetFileName(csvFileName);

    using (OleDbConnection conn =
        new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
        dir + @";Extended Properties=""Text;HDR=Yes;FMT=Delimited"""))
    {
        conn.Open();
        using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM " + name, conn))
        {
            QuoteDataSet ds = new QuoteDataSet();
            adapter.Fill(ds, tableName);
            Console.WriteLine("Num rows loaded is " + ds.Tags.Rows.Count);
            InsertData(ds, tableName);
        }
    }
}

public void InsertData(QuoteDataSet data, String tableName)
{
    using (SQLiteConnection conn = new SQLiteConnection(_connectionString))
    {

        using (SQLiteDataAdapter sqliteAdapter = new SQLiteDataAdapter("SELECT * FROM " + tableName, conn))
        {
            using (new SQLiteCommandBuilder(sqliteAdapter))
            {
                conn.Open();
                Console.WriteLine("Num rows updated is " + sqliteAdapter.Update(data, tableName));
            }
        }
    }
}

Любые намеки на то, почему он не обновляет правильное количество строк?

Обновление:

Я попытался установить команду перед вызовом обновления, и у меня все еще возникает та же проблема... теперь код:

sqliteAdapter.InsertCommand = cmndBldr.GetInsertCommand();
Console.WriteLine("Num rows updated is " + sqliteAdapter.Update(data, tableName));

Когда я отлаживаю его, текст команды: _commandText = "INSERT INTO [Tags] ([tagId], [tagName], [description], [colName], [dataType], [realTime]) VALUES (@param1, @param2, @param3, @param4, @param5, @param6)"

Вот пасти, показывающее состояние набора данных в формате xml: http://pastie.org/936882.


person Kiril    schedule 26.04.2010    source источник
comment
Возможно ли, что вы не установили InsertCommand sql и params? Взгляните на devart .com/dotconnect/sqlite/docs/   -  person Adriaan Stander    schedule 26.04.2010
comment
@astander Я думал, что SQLiteCommandBuilder сделает это на основе этого примера dotnetperls.com/sqlcommandbuilder-example и этот пример devart.com/ точка подключения/sqlite/документы/   -  person Kiril    schedule 26.04.2010
comment
@Link: пожалуйста, оставьте C# в тегах, а не в заголовке.   -  person John Saunders    schedule 26.04.2010
comment
Вот SQLiteDataSet, напечатанный в файле XML: pastie.org/936882 (не то чтобы я не вижу в этом ничего плохого , но это может помочь кому-то дать мне подсказку, если они что-то заметят).   -  person Kiril    schedule 27.04.2010
comment
Не могли бы вы дать мне следующую информацию от отладчика... Когда QDS заполнен, какое имя ds.tables[0]. Как называется таблица, которую вы пытаетесь заполнить? Они одинаковы? если они не совпадают, это может сбить с толку SQLite dataAddapter. Я не совсем уверен, но я думаю, что когда вы сообщаете ему об обновлении на основе набора данных, он сканирует этот набор данных для таблицы с таким же именем, как исходная таблица БД, и выполняет сравнение данных на основе этого   -  person TerrorAustralis    schedule 28.04.2010
comment
@lirik - выложил рабочий код.   -  person Sky Sanders    schedule 28.04.2010
comment
@Dave ds.Tables[0].TableName выводит GPTags, ds.Tables[1].TableName выводит Quotes, ds.Tables[2].TableName выводит Теги... поэтому в моем вызове обновления я указываю таблицу Теги.   -  person Kiril    schedule 28.04.2010


Ответы (2)


Обновление:

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

Но позвольте мне дать вам более чистый способ сделать это с помощью adapter.AcceptChangesDuringFill.

    using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM " + name, conn))
    {
        // this is the proper way to transfer rows
        adapter.AcceptChangesDuringFill = false;

        QuoteDataSet ds = new QuoteDataSet();
        adapter.Fill(ds, tableName);
        Console.WriteLine("Num rows loaded is " + ds.Tags.Rows.Count);
        InsertData(ds, tableName);
    }

Это импортирует 83 строки:

Программа.cs

using System;
using System.Data;
using System.Data.SQLite;

namespace SqliteCsv
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            // fill your dataset
            QuoteDataSet ds = new QuoteDataSet();
            ds.ReadXml("data.xml", XmlReadMode.InferTypedSchema);


            // hack to flag each row as new as per lirik
            // OR just set .AcceptChangesDuringFill=false on adapter
            foreach (DataTable table in ds.Tables)
            {
                foreach (DataRow row in table.Rows)
                {
                    row.SetAdded();
                }
            }

            int insertedRows;
            using (
                SQLiteConnection con =
                    new SQLiteConnection(@"data source=C:\Projects\StackOverflowAnswers\SqliteCsv\SqliteCsv\Quotes.db"))
            {
                con.Open();

                // clear table - you may not want this
                SQLiteCommand cmd = con.CreateCommand();
                cmd.CommandText = "delete from Tags";
                cmd.ExecuteNonQuery();


                using (SQLiteTransaction txn = con.BeginTransaction())
                {
                    using (SQLiteDataAdapter dbAdapter = new SQLiteDataAdapter("select * from Tags", con))
                    {
                        dbAdapter.InsertCommand = new SQLiteCommandBuilder(dbAdapter).GetInsertCommand(true);
                        insertedRows = dbAdapter.Update(ds, "Tags");
                    }
                    txn.Commit();
                }
            }
            Console.WriteLine("Inserted {0} rows", insertedRows);

            Console.WriteLine("Press any key");
            Console.ReadKey();
        }
    }
}

Исходный ответ:

Это источник SQLiteDataAdapter ctor, который в конечном итоге вызывается. Обратите внимание, что построитель команд не используется. Вам нужно явно установить свойство InserCommand в SQLiteDataAdapter, возможно, с помощью SQLiteCommandBuilder?

public SQLiteDataAdapter(string commandText, SQLiteConnection connection)
{
    this.SelectCommand = new SQLiteCommand(commandText, connection);
}
person Sky Sanders    schedule 26.04.2010
comment
@Sky, спасибо ... Я попытался установить InsertCommand вручную и убедился, что он правильно установлен в отладчике (дополнительную информацию см. В моем обновлении), но он все еще не работает. - person Kiril; 26.04.2010
comment
Ах, печально известная проблема, которая до сих пор не работает. Я слышал, что это тяжело. - person Lasse V. Karlsen; 28.04.2010
comment
Довольно сложно решить проблему «все еще не работает». Но я обнаружил, что функция global::DoStuff() творит чудеса в этих случаях. - person TerrorAustralis; 28.04.2010
comment
@ Дэйв, да, старина DoesntWorkException снова наносит удар! meta.stackexchange.com/questions /19478/the-many-memes-of-meta/ - но я думаю, что мне это удалось. ;-) - person Sky Sanders; 28.04.2010
comment
@Sky, я понял проблему: DataAdapter только проверяет, есть ли в DataSet какие-либо флаги, указывающие на то, что он не синхронизирован с базой данных, из которой он был заполнен, и у него нет возможности узнать, что есть изменение, даже если я Я пытаюсь вставить данные в другую базу данных. Мне пришлось вызывать SetAdded для каждой строки... теперь это работает как шарм. Спасибо за ваше время! - person Kiril; 28.04.2010
comment
@Sky, и не похоже, что имена столбцов в качестве параметров имеют какое-либо значение, я пробовал оба, и оба работали нормально ... - person Kiril; 28.04.2010
comment
@lirik - да, я только что заметил единственную реальную разницу, которую я видел между двумя битами кода. Эй, послушай, почему бы мне не обновить свой ответ, включив в него твое исправление, и тогда ты сможешь принять его, иначе награда будет потеряна, так как ты можешь принять свой собственный ответ, но не награду. meta.stackexchange.com/questions/18841/ - person Sky Sanders; 28.04.2010
comment
@Sky звучит хорошо, спасибо за всю вашу помощь ... обновите свой вопрос ответом, и я приму его. - person Kiril; 28.04.2010
comment
@lirik - один лучше - я знал, что чего-то не хватает, и добавил это - AcceptChangesDuringFill - попробуйте это и дайте мне знать, если это сработает для вас. - person Sky Sanders; 28.04.2010
comment
@lirik, о, и знайте, что я не умаляю ваш вывод, когда характеризую его как взлом в обновленном источнике. Это просто рефлекторно, я регулярно помечаю свой собственный код как //HACK: (причина), когда чувствую, что может быть более чистый способ сделать это. ;-) - person Sky Sanders; 28.04.2010
comment
@Sky да, я не знал более любезного решения, но отключение AcceptChangesDuringFill намного лучше. Мне нужно подождать около 9 часов, прежде чем я смогу принять ваш ответ сейчас :). - person Kiril; 29.04.2010

Я смог обойти эту проблему, просматривая каждую строку и изменяя ее состояние, вызывая SetAdded();... после того, как я сделал это, команда Update сработала как шарм.

public void InsertData(QuoteDataSet dataSet, String tableName)
{
    int numRowsUpdated = 0;
    using (SQLiteConnection conn = new SQLiteConnection(_connectionString))
    {
        conn.Open();
        using (SQLiteTransaction transaction = conn.BeginTransaction())
        using (SQLiteDataAdapter sqliteAdapter = new SQLiteDataAdapter("SELECT * FROM " + tableName, conn))
        {
            using (sqliteAdapter.InsertCommand = new SQLiteCommandBuilder(sqliteAdapter).GetInsertCommand())
            {
                var rows = dataSet.Tags.AsEnumerable();
                foreach (var row in rows)
                {
                    row.SetAdded();
                }
                numRowsUpdated = sqliteAdapter.Update(dataSet, tableName);
            }
            transaction.Commit();
        }
    }
    Console.WriteLine("Num rows updated is " + numRowsUpdated);
}

Я предполагаю, что когда DataSet заполняется из файла CSV, а затем я пытаюсь вызвать Update, чтобы вставить данные в базу данных, состояние строки не указывает на какие-либо изменения. Мы должны сообщить DataAdapter, что в DataSet есть изменения, потому что все, что он видит, это отсутствие изменений в DataSet по отношению к CSV-файлу, из которого он был заполнен, и он не понимает, что это совершенно новые строки для база данных, в которую я пытаюсь поместить данные.

person Kiril    schedule 28.04.2010