gpt4 book ai didi

c# - SQLite :memory: database usage with using/dispose

转载 作者:行者123 更新时间:2023-12-03 13:34:23 24 4
gpt4 key购买 nike

我已经包装了我所有的SQL Connectionsusing陈述。

using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand(cmdInsert))
{
//some work
}
}

对于 UnitTests我应该使用 :memory: database ,但 database关闭连接后自动删除。

https://www.sqlite.org/inmemorydb.html

The database is automatically deleted and memory is reclaimed when the last connection to the database closes.



有没有解决方法如何使用 :memory: database并使用 using ?我不想在没有 using 的情况下两次编写完全相同的代码..

完整示例

数据库
public abstract class SqliteBase
{
public string ConnectionString;

protected SqliteBase()
{
SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder
{
DataSource = ":memory:",
ForeignKeys = true,
DefaultTimeout = 3,
DateTimeKind = DateTimeKind.Utc,
Pooling = false
};

ConnectionString = builder.ConnectionString + ";mode=memory;cache=shared";
}

private DbConnection _MemoryConnection;
protected DbConnection GetConnection()
{
try
{
if (_MemoryConnection == null)
{
_MemoryConnection = new SQLiteConnection(ConnectionString);
_MemoryConnection.Open();
}

DbConnection dbConnection = new SQLiteConnection(ConnectionString);
dbConnection.Open();

return dbConnection;
}

catch (Exception ex)
{
throw new Exception("Error opening database connection.", ex);
}
}

/// <summary>
/// Creates a table in the SQL database if it does not exist
/// </summary>
/// <param name="tableName">The name of the table</param>
/// <param name="columns">Comma separated column names</param>
protected void CreateTable(string tableName, string columns)
{
using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand($"create table if not exists {tableName} ({columns})"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}

public class FooDatabase : SqliteBase
{
public FooDatabase()
{
CreateTable("FooTable", "Foo TEXT");
}

public void DoFoo()
{
using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand("Select * from FooTable"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}

单元测试
public static class SQLiteTestSetup
{
public static FooDatabase ClassInit()
{
return new FooDatabase();
}

public static void Cleanup()
{

}
}

public abstract class SQLiteTestBase
{
public static FooDatabase Database { get; set; }

[TestMethod]
public void DoSomeFooTest()
{
Database.DoFoo();
}
}

[TestClass]
public class SQLiteTest : SQLiteTestBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Database = SQLiteTestSetup.ClassInit();
}

[ClassCleanup]
public static void ClassCleanup() => SQLiteTestSetup.Cleanup();
}

异常(exception)
Die Testmethode "....SQLiteTest.DoSomeFooTest" hat eine Ausnahme ausgelöst: 
System.Data.SQLite.SQLiteException: SQL logic error
no such table: FooTable
bei System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, String strSql, SQLiteStatement previous, UInt32 timeoutMS, String& strRemain)
bei System.Data.SQLite.SQLiteCommand.BuildNextCommand()
bei System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
bei System.Data.SQLite.SQLiteDataReader.NextResult()
bei System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
bei System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
bei System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
bei System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
bei ....FooDatabase.DoFoo() in ...\SqliteDatabaseBase.cs:Zeile 83.
bei ....SQLiteTestBase.DoSomeFooTest() in ...\SQLiteTest.cs:Zeile 30.

最佳答案

工作解决方案方法

我添加了一个 ConnectionContext类,我可以在其中设置一个标志来决定是否要处理我的 DbConnection或不。

数据库类

public class ConnectionContext : IDisposable
{
private readonly bool _ContextOwnsConnection;
public readonly DbConnection Connection;

public ConnectionContext(DbConnection connection, bool contextOwnsConnection)
{
Connection = connection;
_ContextOwnsConnection = contextOwnsConnection;
}

public void Dispose()
{
if(_ContextOwnsConnection)
Connection.Dispose();
}
}

public abstract class SqliteBase
{
public Func<ConnectionContext> GetContext;

private ConnectionContext _GetConnectionContext()
{
return new ConnectionContext(GetConnection(), true);
}
private string _ConnectionString;
private readonly string _Dbfile;

protected SqliteBase()
{
GetContext = _GetConnectionContext;
_Dbfile = ":memory:";

_InitConnectionString();
}

private void _InitConnectionString()
{
SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder
{
DataSource = _Dbfile,
ForeignKeys = true,
DefaultTimeout = 3,
DateTimeKind = DateTimeKind.Utc,
Pooling = true
};

_ConnectionString = builder.ConnectionString;
}

public DbConnection GetConnection()
{
try
{
DbConnection dbConnection = SQLiteFactory.Instance.CreateConnection();
dbConnection.ConnectionString = _ConnectionString;
dbConnection.Open();

return dbConnection;
}

catch (Exception ex)
{
throw new Exception("Error opening database connection.", ex);
}
}

/// <summary>
/// Creates a table in the SQL database if it does not exist
/// </summary>
/// <param name="tableName">The name of the table</param>
/// <param name="columns">Comma separated column names</param>
protected void CreateTable(string tableName, string columns)
{
using (ConnectionContext context = GetContext())
{
using (DbCommand dbCommand = context.Connection.CreateCommand($"create table if not exists {tableName} ({columns})"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}

public class FooDatabase : SqliteBase
{
public FooDatabase()
{
Initialize();
}

public void Initialize()
{
CreateTable("FooTable", "Foo TEXT");
}

public void DoFoo()
{
using (ConnectionContext context = GetContext())
{
using (DbCommand dbCommand = context.Connection.CreateCommand("Select * from FooTable"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}

单元测试
public abstract class SQLiteTestBase
{
public static ConnectionContext Connection { get; set; }
public static FooDatabase Database { get; set; }

[TestMethod]
public void DoSomeFooTest()
{
Database.DoFoo();
}
}

[TestClass]
public class SQLiteTest : SQLiteTestBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Database = new FooDatabase();
Database.GetContext = () => Connection;
Connection = new ConnectionContext(Database.GetConnection(), false);
}

[TestInitialize]
public void TestInit()
{
Connection = new ConnectionContext(Database.GetConnection(), false);
Database.Initialize();
}

[TestCleanup]
public void TestCleanup()
{
Connection.Dispose();
Connection = null;
}
}

关于c# - SQLite :memory: database usage with using/dispose,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48925483/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com