为什么HQL到SQLite数据库中的NHibernate simple select不起作用?
我最近开始使用FluenHibernate,当我试图用SQLite编写单元测试时,出现了一些奇怪的问题 我使用SQLite内存数据库进行测试,对于每个测试方法,我都会清除数据库中存在的数据。例如:为什么HQL到SQLite数据库中的NHibernate simple select不起作用?,nhibernate,sqlite,hql,Nhibernate,Sqlite,Hql,我最近开始使用FluenHibernate,当我试图用SQLite编写单元测试时,出现了一些奇怪的问题 我使用SQLite内存数据库进行测试,对于每个测试方法,我都会清除数据库中存在的数据。例如: var u = new User() { Name = "Piotr" }; _session.Save(u); _session.Clear(); var list = _session.CreateCriteria<User>().List(); 我得到: System.Data.S
var u = new User() { Name = "Piotr" };
_session.Save(u);
_session.Clear();
var list = _session.CreateCriteria<User>().List();
我得到:
System.Data.SQLite.SQLiteException: SQLite error
no such table: users
NHibernate生成的sql查询很好,那么会有什么问题呢?可能是名称多元化?用户-用户。您提到您正在使用内存中的SQLite数据库。NHibernate可能决定关闭这两条语句之间的数据库连接,这将导致丢失所有表 防止这种情况的一种方法是创建自定义IConnectionProvider实现,该实现允许您显式控制连接何时关闭 以下是我在项目中处理此问题的方法:
public class InMemoryConnectionProvider : IConnectionProvider
{
private static readonly object syncObject = new object();
private static SQLiteConnection connection;
#region IConnectionProvider Members
public void Configure(IDictionary<string, string> settings)
{
}
public void CloseConnection(IDbConnection conn)
{
}
public IDbConnection GetConnection()
{
CreateConnection();
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
return connection;
}
public IDriver Driver
{
get { return new SQLite20Driver(); }
}
public void Dispose()
{
}
#endregion
public static void CreateConnection()
{
lock (syncObject)
{
if (connection == null)
{
var builder = new SQLiteConnectionStringBuilder
{
DataSource = ":memory:",
BinaryGUID = true,
DateTimeFormat = SQLiteDateFormats.ISO8601
};
connection = new SQLiteConnection(builder.ConnectionString);
connection.Open();
}
}
}
public static void DestroyConnection()
{
lock (syncObject)
{
if (connection != null)
{
connection.Dispose();
connection = null;
}
}
}
}
MemoryConnectionProvider中的公共类:IConnectionProvider
{
私有静态只读对象syncObject=新对象();
私有静态SQLiteConnection;
#区域IConnectionProvider成员
公共无效配置(IDictionary设置)
{
}
公共连接(IDbConnection conn)
{
}
公共IDbConnection GetConnection()
{
CreateConnection();
if(connection.State!=ConnectionState.Open)
{
connection.Open();
}
回路连接;
}
公共驾驶员
{
获取{返回新的SQLite20Driver();}
}
公共空间处置()
{
}
#端区
公共静态void CreateConnection()
{
锁定(同步对象)
{
if(连接==null)
{
var builder=new-SQLiteConnectionStringBuilder
{
DataSource=“:内存:”,
BinaryGUID=true,
DateTimeFormat=SQLiteDateFormats.ISO8601
};
连接=新的SQLiteConnection(builder.ConnectionString);
connection.Open();
}
}
}
公共静态连接()
{
锁定(同步对象)
{
if(连接!=null)
{
connection.Dispose();
连接=空;
}
}
}
}
您还需要在配置文件中设置connection.provider
选项以指向此类
在测试中,您可以在测试开始时或在安装方法中调用静态
InMemoryConnectionProvider.CreateConnection()
方法。完成后,可以调用MemoryConnectionProvider.DestroyConnection()中的来关闭连接。由于IConnectionProvider.CloseConnection()的实现是不可操作的,NHibernate将无法自行关闭连接。我在使用内存数据库时遇到了SQLite问题。连接/会话关闭时,数据库将被销毁。使用文件变量似乎效果更好
此外,数据库实体必须作为会话工厂设置的一部分创建。在会话工厂设置中尝试以下操作:
// Create schema.
new SchemaExport(config).Create(false, true);
在再次获取列表之前,您可以尝试刷新会话。很抱歉,没有看到错误。可能会混淆数据库表名User和映射中给出的名称。您必须使用映射中的名称,而不是表名。第二个查询真的是代码中的下一行吗?您确定第二个查询不在另一个会话上吗?因此,为了澄清,如果我随意启动和处理ISession,那么数据库肯定不会跨ISession存在?如果是这样,它将解释为什么在创建任何ISession之前,当我尝试将架构推送到内存中的数据库时,会得到“没有这样的表”,或者,如果我在*.hbm.xml文件中指定架构,“未知数据库”。这可能是“没有这样的表”错误的原因。不过,“未知数据库”听起来像是别的东西。SQLite不支持模式,但我认为NHibernate的当前版本通过使用下划线而不是点来伪造它(即,“schema_table”而不是“schema.table”)。如果您使用的是旧版本,或者没有配置SQLite方言,那么它可能会尝试使用点,SQLite将其解释为试图通过ATTACH database语句访问另一个附加的数据库(我假设您没有这样做)。
// Create schema.
new SchemaExport(config).Create(false, true);