c# - C#SQLite事务-此用法有效吗?

标签 c# sqlite transactions

我已经开始涉猎C#,并且正在编写一段代码来处理将两个表插入到SQLite数据库中的情况,如果所涉及的平台尚不存在,则仅为“平台”插入行。

该代码按预期工作,但是我正在寻求有关是否正确处理事务的验证。

还要感谢任何指向时髦或可以改进的指针。

谢谢

private static string databaseFilePath = @"Data\";
private static string databaseFileName = "myDB.db";
private static string databaseFullPath = String.Concat(databaseFilePath, databaseFileName);
private static string platformTableName = "Platforms";
private static string gameTableName = "Games";

// Create our tables
private async void CreateTables(SQLiteConnection connection, SQLiteTransaction transaction)
{
    // SQLite query string to create the Platform table
    string createPlatformTableQuery = @"CREATE TABLE IF NOT EXISTS [" + platformTableName + @"] (
        [Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        [Name] TEXT NOT NULL,
        [ShortCode] TEXT NOT NULL,
        [Description] TEXT NOT NULL,
        [ReleaseDate] TEXT NOT NULL,
        [Images] TEXT NOT NULL,
        [Video] TEXT NOT NULL,
        [RomPaths] TEXT NOT NULL
    )";

    // SQLite query string to create the Games table
    string createGamesTableQuery = @"CREATE TABLE IF NOT EXISTS [" + gameTableName + @"] (
        [Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        [Platform] TEXT NOT NULL,
        [Name] TEXT NOT NULL,
        [Crc] TEXT NOT NULL,
        [Screenshots] TEXT NOT NULL,
        [FanArt] TEXT NOT NULL,
        [BoxArt] TEXT NOT NULL,
        [CartArt] TEXT NOT NULL,
        [DiscArt] TEXT NOT NULL,
        [Music] TEXT NOT NULL,
        [Video] TEXT NOT NULL,
        [Players] INTEGER NOT NULL,
        [Description] TEXT NOT NULL,
        [ReleaseDate] TEXT NOT NULL,
        [Publisher] TEXT NOT NULL,
        [Developer] TEXT NOT NULL,
        [Rating] TEXT NOT NULL,
        [PlayCount] INTEGER NOT NULL,
        [PlayTime] REAL NOT NULL,
        [FilePath] TEXT NOT NULL
    )";

    // Create an SQLite command
    using (SQLiteCommand command = new SQLiteCommand(connection))
    {
        try
        {
            // Set the command to create our platform table
            command.CommandText = createPlatformTableQuery;
            // Execute the query
            await command.ExecuteNonQueryAsync();

            // Set the command to create our games table
            command.CommandText = createGamesTableQuery;
            // Execute the query
            await command.ExecuteNonQueryAsync();
        }
        // We encountered an exception
        catch (SQLiteException e)
        {
            // Rollback the transaction
            transaction.Rollback();
            // Throw the exception
            throw e;
        }
    }
}

// Insert Platforms (defined in PlatformList.cs) into the platforms table
private async void InsertPlatforms(SQLiteConnection connection, SQLiteTransaction transaction, PlatformList platformList)
{
    // Is this a fresh population of the Platforms table data?
    bool freshPopulation = false;

    // Create an SQLite command
    using (SQLiteCommand command = new SQLiteCommand(connection))
    {
        try
        {
            command.CommandText = "SELECT COUNT(*) from " + platformTableName;
            var count = await command.ExecuteScalarAsync();
            freshPopulation = Convert.ToInt16(count) <= 0;
        }
        // We encountered an exception
        catch (SQLiteException e)
        {
            // Rollback the transaction
            transaction.Rollback();
            // Throw the exception
            throw e;
        }
    }

    // Loop through the platform list
    foreach (var item in platformList.list)
    {
        // Populate an array from all items in each platformList entry
        string[] values = new string[]
        {
            item.name, item.shortCode, item.description, item.releaseDate, item.images, item.video
        };
        // Comma quote the values
        string commaQuotedValues = "'" + String.Join("','", values) + "'";
        string commandText = String.Concat("INSERT INTO ", platformTableName, " (Name, ShortCode, Description, ReleaseDate, Images, Video) Values (", commaQuotedValues, ")");

        // Create an SQLite command
        using (SQLiteCommand command = new SQLiteCommand(connection))
        {
            try
            {
                // If this is the first time we are inserting data into the platforms table
                if (freshPopulation)
                {
                    // Set the command text
                    command.CommandText = commandText;
                    // Execute the query
                    await command.ExecuteNonQueryAsync();
                }
                // There is already data in the platforms table.. Let's ensure that it's up to date
                else
                {
                    // Set the command to select an existing row from the platforms table (if it exists)
                    command.CommandText = @"SELECT ShortCode FROM " + platformTableName + " WHERE ShortCode='" + item.shortCode + "'";

                    // Start the data reader
                    using (SQLiteDataReader reader = command.ExecuteReader())
                    {
                        // If this row isn't already inserted into the database
                        if (!reader.HasRows)
                        {
                            // Insert any rows not already inserted into the platforms table
                            using (SQLiteCommand insertCommand = new SQLiteCommand(connection))
                            {
                                try
                                {
                                    // Set the command text
                                    insertCommand.CommandText = commandText;
                                    // Execute the query
                                    await insertCommand.ExecuteNonQueryAsync();
                                }
                                // We encountered an exception
                                catch (SQLiteException e)
                                {
                                    // Rollback the transaction
                                    transaction.Rollback();
                                    // Throw the exception
                                    throw e;
                                }
                            }
                        }
                    }
                }
            }
            // We encountered an exception
            catch (SQLiteException e)
            {
                // Rollback the transaction
                transaction.Rollback();
                // Throw the exception
                throw e;
            }
        }
    }
}

// Init
public async void Init()
{
    // Create an instance of the platform list
    PlatformList platformList = new PlatformList();

    // If the database doesn't exist
    if (!File.Exists(databaseFullPath))
    {
        // Create the database
        SQLiteConnection.CreateFile(databaseFullPath);
    }

    // Create an SQLite connection to the database
    using (SQLiteConnection connection = new SQLiteConnection(@"data source=" + databaseFullPath))
    {
        // Open the connection to the database
        await connection.OpenAsync();

        // Start a transaction
        using (SQLiteTransaction transaction = connection.BeginTransaction())
        {
            // Create the required tables
            CreateTables(connection, transaction);

            // Insert platforms into the Platforms table
            InsertPlatforms(connection, transaction, platformList);

            // Commit the transaction
            transaction.Commit();
        }
    }
}

最佳答案

如果代码由于任何异常异常中止,则事务未完成;您不应将回滚限制为SQLiteException

要重新抛出当前异常,应使用throw;而不指定异常对象。否则,异常信息(堆栈跟踪等)将被重置。

在SQLite中,一个连接只能有一个事务,因此您不需要告诉命令对象要使用哪个事务(其他数据库可能会有所不同)。

要回滚事务,您只需要一个try / catch,应该在创建事务时完成(删除所有其他catch es):

using (var transaction = connection.BeginTransaction())
{
    try
    {
        CreateTables(connection);
        InsertPlatforms(connection, platformList);
    }
    catch (Exception e)
    {
        transaction.Rollback();
        throw;
    }
    transaction.Commit();
}

关于c# - C#SQLite事务-此用法有效吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42047887/

相关文章:

c# - 为什么在C#中创建列表会导致此错误?

c# - C#设置所有对象的背景色

ios - SQLite 页面缓存不断增长——性能下降

php - Laravel 没有提交我的第二笔交易

sql-server - SQL Server 中的事务大小限制

spring - @Transactional 方面的建议可能吗?

c# - 将连接字符串从 app.config 移动到 C# 中的代码

c# - DbContext 的 ObjectContext.ApplyCurrentValues 的等价物是什么

python - 如何确保在调试期间关闭 sqlite 数据库连接?

android - 向应用程序提供 Quadtree GPS 数据的最佳选择?