我已经开始涉足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();
}
}
}
答案 0 :(得分:2)
如果代码因任何异常而中止,则事务未完成;您不应该将回滚限制为SQLiteException
s。
要重新抛出当前异常,您应该使用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();
}