简体   繁体   English

C# SQLite 连接关闭

[英]C# SQLite connection closing

So I'm moving into storing data locally using SQLite and want to make sure I'm doing this the right way.所以我开始使用 SQLite 在本地存储数据,并希望确保我以正确的方式执行此操作。

What is the best practice for handling this type of operation?处理此类操作的最佳做​​法是什么? I am trying to create a reusable connection and close it when I am finished with command.Dispose();我正在尝试创建一个可重用的连接并在我完成command.Dispose();后关闭它command.Dispose(); . . Is this the correct way to do it, or should I be creating the connection a different way?这是正确的方法,还是应该以不同的方式创建连接?

using System.Data.SQLite;

public class DB
{

        public static SQLiteConnection ConnectDB()
        {
            var m_dbConnection = new SQLiteConnection("Data Source=MyDatabase.sqlite;Version=3;");
            m_dbConnection.Open();
            return m_dbConnection;
        }

        public static void CreateTable()
        {

            string sql = "CREATE TABLE highscores (name VARCHAR(20), score INT)";
            SQLiteCommand command = new SQLiteCommand(sql, ConnectDB());
            command.ExecuteNonQuery();
            MessageBox.Show("Table created");
            command.Dispose();
            
        }
}

In response to the comments, is the using statement used on CreateTable() and does Dispose() not have to be used as shown below?针对评论,是否在CreateTable()上使用了 using 语句,是否不必使用如下所示的Dispose()

    public static void CreateTable()
        {

            string sql = "CREATE TABLE highscores (name VARCHAR(20), score INT)";
            using (SQLiteCommand command = new SQLiteCommand(sql, ConnectDB()))
            {
                command.ExecuteNonQuery();
                MessageBox.Show("Table created");
            }
}
            

Looks reasonable, but you should be using a close rather than a dispose.看起来很合理,但您应该使用 close 而不是 dispose。 A better version would be something like更好的版本应该是这样的

public class DB
{
    /// <summary>
    /// Create a new database connection
    /// </summary>
    /// <param name="src">An optional connection string, if null or empty the default will be used</param>
    /// <returns>A database connection</returns>
    public static SqliteConnection ConnectDB(string src = null)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(src))
                src = "Data Source=MyDatabase.sqlite;Version=3;";
            SqliteConnection dbConnection = new SqliteConnection("Data Source=MyDatabase.sqlite;Version=3;");
            dbConnection.Open();
            return dbConnection;
        }
        catch(System.Exception ex)
        {
            // Add logging here
            throw ex;
            // or just throw to re-throw the original error
        }
    }
    /// <summary>
    /// Close the database connection
    /// </summary>
    /// <param name="dbConnection"></param>
    public static void CloseConnection(SqliteConnection dbConnection)
    {
        try
        {
            if (dbConnection != null)
                dbConnection.Close();
        }
        catch (System.Exception ex)
        {
            // Add logging here, don't throw
        }
    }
    /// <summary>
    /// Execute a non query and returns the number of rows updated. Use this for create, drop, insert, delete and update commands
    /// </summary>
    /// <param name="sqlCmd">The SQL command to execute</param>
    /// <param name="dbConnection">The database connection to use, if null an new connection will be opened and closed afterwards</param>
    /// <param name="conString">An optional DB connection string</param>
    /// <returns>The number of rows updated</returns>
    public static async Task<int> ExecuteNonQuery(string sqlCmd, SqliteConnection dbConnection = null, string conString = null)
    {
        SqliteTransaction txn = null;
        bool openedCon = false;
        int result = 0;
        try
        {
            if (dbConnection == null)
            {
                dbConnection = ConnectDB();
                openedCon = true;
            }

            SqliteCommand command = new SqliteCommand(sqlCmd, dbConnection);
            txn = command.Transaction;
            result = await command.ExecuteNonQueryAsync();
            await txn.CommitAsync();
        }
        catch (System.Exception ex)
        {
            if(txn != null)
            {
                await txn.RollbackAsync();
            }
            // Add logging here
            throw ex;
            // or just throw to re-throw the original error
        }
        finally
        {
            if (openedCon)
                CloseConnection(dbConnection);
        }
        return result;
    }

    /// <summary>
    /// Execute a command and return the result set in a data reader
    /// </summary>
    /// <param name="sqlCmd">The select to execute</param>
    /// <param name="dbConnection">The database connection to use, if null an new connection will be opened and closed afterwards</param>
    /// <param name="conString">An optional DB connection string</param>
    /// <returns>SqliteDataReader with results</returns>
    public static async Task<SqliteDataReader> ExecuteQuery(string sqlCmd, SqliteConnection dbConnection = null, string conString = null)
    {
        SqliteDataReader res = null;
        bool openedCon = false;
        try
        {
            if (dbConnection == null)
            {
                dbConnection = ConnectDB(conString);
                openedCon = true;
            }
            SqliteCommand command = new SqliteCommand(sqlCmd, dbConnection);
            res = await command.ExecuteReaderAsync();
        }
        catch (System.Exception ex)
        {
            res = null;
            // Add logging here
            throw ex;
            // or just throw to re-throw the original error
        }
        finally
        {
            if (openedCon)
                CloseConnection(dbConnection);
        }
        return res;
    }
    /// <summary>
    /// Run a query and return the value in the first row, first column as an object
    /// </summary>
    /// <param name="sqlCmd">The select to execute</param>
    /// <param name="dbConnection">The database connection to use, if null an new connection will be opened and closed afterwards</param>
    /// <param name="conString">An optional DB connection string</param>
    /// <returns>The value in the first row, first column as an object</returns>
    public static async Task<object> ExecuteScalar(string sqlCmd, SqliteConnection dbConnection = null, string conString = null)
    {
        object res = null;
        bool openedCon = false;
        try
        {
            if (dbConnection == null)
            {
                dbConnection = ConnectDB(conString);
                openedCon = true;
            }
            SqliteCommand command = new SqliteCommand(sqlCmd, dbConnection);
            res = await command.ExecuteScalarAsync();
        }
        catch (System.Exception ex)
        {
            res = null;
            // Add logging here
            throw ex;
        }
        finally
        {
            if (openedCon)
                CloseConnection(dbConnection);
        }
        return res;
    }
}

You can use it something like this;你可以像这样使用它;

static async Task Main(string[] args)
{
     SqliteConnection con = null;
     try
     {
         con = DB.ConnectDB();
         int rowCount = await DB.ExecuteNonQuery("CREATE TABLE highscores (name VARCHAR(20), score INT)", con);
         rowCount = await DB.ExecuteNonQuery("INSERT INTO highscores(name, score) VALUES ('first', 1)", con);
         SqliteDataReader res = await DB.ExecuteQuery("SELECT * FROM highscores", con);
         string maxName = (string)await DB.ExecuteScalar("SELECT max(name) FROM highscores", con);
     }
     catch (System.Exception ex)
     {
         // Resolve issue here
     }
     finally
     {
         if(con != null)
             DB.CloseConnection(con);
     }
}

You don't need to specifically call the dispose, when the connection object (con in this example) goes out of scope, the dispose will be called for you.您不需要专门调用dispose,当连接对象(在本例中为con)超出范围时,将为您调用dispose。 Just call Close to terminate the connection.只需调用 Close 即可终止连接。

You could open the connection in a using block, that is up to you, but you still should close the connection before the end of the using.您可以在 using 块中打开连接,这取决于您,但您仍然应该在 using 结束之前关闭连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM