【问题标题】:SQLiteDataAdapter Update method returning 0SQLiteDataAdapter 更新方法返回 0
【发布时间】:2011-02-12 06:03:35
【问题描述】:

我从我的 CSV 文件中加载了 83 行,但是当我尝试更新 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

【问题讨论】:

  • 是不是你没有设置InsertCommand sql和params?快速浏览devart.com/dotconnect/sqlite/docs/…
  • @astander 我认为 SQLiteCommandBuilder 会根据这个例子 dotnetperls.com/sqlcommandbuilder-example 和这个例子 devart.com/dotconnect/sqlite/docs/… 来做到这一点
  • @Link: 请把“C#”留在标签里,不要离开标题。
  • 这是打印在 XML 文件中的 SQLiteDataSet:pastie.org/936882(并不是说我发现它有任何问题,但如果有人注意到某些问题,它可能会帮助我提示)。
  • 能否请您从调试器中给我以下信息... QDS 填满后,ds.tables[0].name 是什么。您要填写的表格的名称是什么?他们是一样的吗?如果它们不相同,那么这可能会使 SQLite dataAddapter 感到困惑。我不完全确定,但我认为当您告诉它基于数据集进行更新时,它会扫描该数据集以查找与源数据库表同名的表,并根据该表进行数据比较

标签: c# sqlite ado.net dataadapter


【解决方案1】:

更新

阅读您的解决方案后,让我说我很尴尬,我没有抓住那个。枚举行以将行状态设置为添加将起作用。

但是让我给你一个更简洁的方法来使用 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 的来源。请注意,没有使用命令生成器。您需要在 SQLiteDataAdapter 上显式设置 InserCommand 属性,或许可以使用 SQLiteCommandBuilder?

public SQLiteDataAdapter(string commandText, SQLiteConnection connection)
{
    this.SelectCommand = new SQLiteCommand(commandText, connection);
}

【讨论】:

  • @Sky,谢谢...我尝试手动设置 InsertCommand 并验证它在调试器中设置正确(有关更多信息,请参阅我的更新),但它仍然无法正常工作。
  • 啊,臭名昭著的“它仍然无法正常工作”的问题。我听说这很难。
  • 很难解决“它仍然无法正常工作”的问题。但是我发现函数 global::DoStuff() 在这些情况下可以创造奇迹
  • @Dave 是的,老大'DoesntWorkException 又来了! meta.stackexchange.com/questions/19478/the-many-memes-of-meta/… - 但我想我被鞭打了。 ;-)
  • @Sky,我发现了问题:DataAdapter 仅检查 DataSet 是否有任何标志表明它与填充它的数据库不同步,并且无法知道即使我试图将数据插入不同的数据库,也会发生变化。我不得不为每一行调用 SetAdded ......它现在就像一个魅力。感谢您的宝贵时间!
【解决方案2】:

我能够通过遍历每一行并通过调用 SetAdded(); 更改其状态来解决此问题...在我这样做之后,更新命令就像一个魅力。

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 文件没有任何变化,并且它没有意识到这些是我尝试将数据放入的数据库的全新行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多