我有一个 .net 测试应用程序,它创建表,使用它们,然后多次删除它们。
当我使用 Firebird ADO.Net Data Provider 5.9.1 对 Firebird 3.0.2 数据库运行此应用程序时,它立即失败,因为它必须创建一个与之前删除的同名的表:表确实存在!
重新启动应用程序可以避免麻烦,但我不想在每次测试后重新启动它。
这个问题非常相似,但只是悬而未决,直接使用 Firebirdisql
工具而不是 .Net 应用程序。
有没有办法在不重新启动应用程序的情况下实际删除 Firebird 中的表?
此应用程序测试许多其他数据库,但没有此问题:SQL-Server、SQL-Server Compact Edition、MySql、SQLite、Oracle、PostgreSQL。
这是 Firebird 的 MCVE 失败。用合适的代码替换前两行以获得连接字符串。所有其他代码只是 Firebird ADO.Net 数据提供者和 NUnit。它并没有完全像我的实际应用程序那样失败,但我认为这是相同的潜在问题。
[Test]
public void CreateSelectDrop()
{
var cfg = TestConfigurationHelper.GetDefaultConfiguration();
var cnxStr = cfg.Properties[Environment.ConnectionString];
using (var cnx = new FbConnection(cnxStr))
{
cnx.Open();
using (var tran = cnx.BeginTransaction())
{
using (var cmd = cnx.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "create table test (id int not null primary key)";
cmd.ExecuteNonQuery();
}
tran.Commit();
}
}
using (var cnx = new FbConnection(cnxStr))
{
cnx.Open();
using (var tran = cnx.BeginTransaction())
{
using (var cmd = cnx.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into test (id) values (1)";
cmd.ExecuteNonQuery();
}
tran.Commit();
}
}
using (var cnx = new FbConnection(cnxStr))
{
cnx.Open();
using (var tran = cnx.BeginTransaction())
{
using (var cmd = cnx.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select id from test";
using (var reader = cmd.ExecuteReader())
{
Assert.IsTrue(reader.Read());
Assert.AreEqual(1, reader.GetInt32(0));
Assert.IsFalse(reader.Read());
}
}
tran.Commit();
}
}
using (var cnx = new FbConnection(cnxStr))
{
cnx.Open();
using (var tran = cnx.BeginTransaction())
{
using (var cmd = cnx.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "delete from test";
cmd.ExecuteNonQuery();
}
tran.Commit();
}
}
using (var cnx = new FbConnection(cnxStr))
{
cnx.Open();
using (var tran = cnx.BeginTransaction())
{
using (var cmd = cnx.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "drop table test";
cmd.ExecuteNonQuery();
}
tran.Commit();
}
}
}
仅从表中选择是不够的。只有在我将删除添加到测试中后,问题才出现。它在最后一次事务提交时失败,即丢弃的一个,并带有消息:
FirebirdSql.Data.FirebirdClient.FbException : lock conflict on no wait transaction
unsuccessful metadata update
object TABLE "TEST" is in use
----> FirebirdSql.Data.Common.IscException : lock conflict on no wait transaction
unsuccessful metadata update
object TABLE "TEST" is in use
at FirebirdSql.Data.FirebirdClient.FbTransaction.Commit()
at NHibernate.Test.DialectTest.FirebirdDialectFixture.CreateSelectDrop()
根据Nathan Brown 在 Github 讨论中的说法,这个麻烦似乎仅限于 Firebird ADO.Net 数据提供者。他将范围缩小到从 2.7.7 版本切换到 3.0.0。