1

将记录插入 SQLite 表时,我遇到了一个奇怪的错误。这是来自客户的日志:

Microsoft.Data.Sqlite.SqliteException: SQLite Error 19: 'NOT NULL constraint failed: Events.details'.
   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteNonQuery()
   at SqliteDemo.LogEvent(...) in ...

诊断的相关位显然是这样的:

SQLite Error 19: 'NOT NULL constraint failed: Events.details'

…这似乎很清楚,除了一件事:该details列缺少NOT NULL约束:

CREATE TABLE IF NOT EXISTS Events (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name STRING NOT NULL,
    time INTEGER NOT NULL,
    code INTEGER NOT NULL,
    details STRING,
    message STRING NOT NULL,
    status INTEGER NOT NULL )

我不知道插入失败的值,因此下一步显然是改进我的诊断并等待它再次发生。或者我可以添加空守卫以确保它不再发生并忘记整个事情。

但我很好奇:

  • SQLite 的诊断是否有可能出错,并且它是 NOT NULL真正的罪魁祸首之一?
  • 为什么我的单元测试没有空detail值问题?
  • 这可能与 SQLite 的动态输入方法有关吗?
  • ……或者完全不同的东西?

有任何想法吗?

环境

  • 面向 Windows 10 上的 .NET Framework 4.8
  • 使用Microsoft.Data.Sqlite5.0.14
    (不是System.Data.SQLite——尽管我不确定区别是否相关)。

代码

我不能在这里发布我们的生产代码。相反,这是一个完整的、独立的 C# 程序,我相信它在所有相关方面都与生产代码非常相似。

using System;
using Microsoft.Data.Sqlite;

class SqliteDemo
{
    static void Main()
    {
        SqliteDemo demo = new SqliteDemo();
        demo.LogEvent("name 1", DateTime.Now, 42, "details", "message 1", 0);
        demo.LogEvent("name 2", DateTime.Now, 42, null, "message 2", 0); //*** Works...
    }

    readonly string connectionString = new SqliteConnectionStringBuilder
    {
        DataSource = "Test.db",
        Mode = SqliteOpenMode.ReadWriteCreate,
    }.ConnectionString;

    const string CreateTableSql =
        @"CREATE TABLE IF NOT EXISTS Events (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name STRING NOT NULL,
            time INTEGER NOT NULL,
            code INTEGER NOT NULL,
            details STRING,
            message STRING NOT NULL,
            status INTEGER NOT NULL
        )";

    int LogEvent(string name, DateTime time,
            int code, string details, string message, short status)
    {
        using (SqliteConnection connection = CreateOpenConnection())
        {
            using (SqliteCommand command = CreateCommand(connection,
                "INSERT INTO Events(name, time, code, details, message, status) " +
                "VALUES(@name, @time, @code, @details, @message, @status)"))
            {
                AddParameter(command, "name", name);
                AddParameter(command, "time", time);
                AddParameter(command, "code", code);
                AddParameter(command, "details", details);
                AddParameter(command, "message", message);
                AddParameter(command, "status", status);

                return command.ExecuteNonQuery(); //*** SOMETIMES throws
            }
        }
    }

    static void AddParameter(SqliteCommand command, string name, object value)
    {
        command.Parameters.Add(new SqliteParameter(name, value ?? DBNull.Value));
    }

    static SqliteCommand CreateCommand(SqliteConnection connection, string sql)
    {
        SqliteCommand command = connection.CreateCommand();
        command.CommandText = sql;
        return command;
    }

    SqliteConnection CreateOpenConnection()
    {
        SqliteConnection connection = new SqliteConnection(connectionString);
        connection.Open();
        CreateTableIfNecessary(connection);
        return connection;
    }

    void CreateTableIfNecessary(SqliteConnection connection)
    {
        using (SqliteCommand command = CreateCommand(connection, CreateTableSql))
        {
            command.ExecuteNonQuery();
        }
    }
}
4

1 回答 1

1

从您的代码看来,您正在传递message给您的过程,在一种情况下,它的值是null. 但是在create table脚本中,您有一个约束message STRING NOT NULL,它会在插入时引发错误(因为null不允许message列)。尝试把empty string,而不是,null看看是否出现同样的错误。

于 2022-02-10T22:34:12.337 回答