我在内存中遇到了一些Sqlite问题。
我有一个有CPF字段的类 - 类似于美国的SSN。作为商业规则,CPF在系统中必须是唯一的。
所以我决定检查有这个字段的类。现在也许这里有代码味道:如果这是一个冲突的CPF,我会检查ORM。
private CPF cpf;
public virtual CPF CPF
{
get { return cpf; }
set
{
if (this.ormCreated) //Do not check if it is loaded from the DB. Otherwise, it loops, generating a StackOverflow exception
{
cpf = value;
}
else
{
this.setNewCpf(value);
}
}
}
private void setNewCpf(CPF newCpf)
{
if (this.cpf == newCpf)
{
return;
}
if (Helper.Orm.IsConflictingCpf(newCpf))
{
throw new ConflictingCpfException();
}
else
{
cpf = newCpf;
}
}
这是ORM Helper类的实现。
bool OrmHelper.IsConflictingCpf(CPF cpf)
{
int? cpfNumber = cpf.NumeroSemDV;
if (cpfNumber.HasValue)
{
var teste = findByCpfNumber<Client>(cpf);
return
(
findByCpfNumber<Client>(cpf) != null ||
findByCpfNumber<Adversary>(cpf) != null
);
}
else
{
//CPFSemDV = Nullable
return false;
}
}
private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
using (var session = this.NewSession())
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
session.Close();
}
}
return null;
}
问题发生在我的测试中。我正在使用FluentNHibernate和内存SQLite。
protected override FluentConfiguration PersistenceProvider
{
get
{
return Fluently
.Configure()
.Database(
SQLiteConfiguration
.Standard
.InMemory()
.ShowSql()
);
}
}
这是失败的测试。
protected override void Given()
{
base.Given();
var clients = new List<Client>();
Client client1 = new Client("Luiz Angelo Heinzen")
{
Capaz = true,
CPF = new CPF(18743509),
eMail = "lah@furb.br"
};
session.Save(client1);
session.Evict(client1);
}
[Then]
public void Motherfaker()
{
Client fromDb;
var clientsFromDb = session.Query<Client>()
.Where(c => c.eMail == "lah@furb.br");
fromDb = clientsFromDb.FirstOrDefault<Client>();
Assert.AreEqual(fromDb.FullName, "Luiz Angelo Heinzen");
}
它失败的原因?一开始它失败了,因为表不存在。在内存中,sqlite会破坏每个新会话的架构。所以我更改了代码以在NewSession()上返回相同的会话。但现在它因NHibernate异常而失败:会话已关闭。我已经测试了,如果从这个
更改findByCpfNumber private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
using (var session = this.NewSession())
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
session.Close();
}
}
return null;
}
到这个
private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
//using (var session = this.NewSession())
var session = this.NewSession();
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
//session.Close();
this.CloseSession(session);
}
}
this.CloseSession(session);
return null;
}
错误不再发生。显然,我必须实现CloseSession方法。它将关闭生产数据库上的会话,如果使用Sqlite,它将不执行任何操作。
但是我宁愿在某种程度上配置SQLite它不会处理会话。我已经阅读了关于release_mode,Pooling和Max Pool属性的here。但我似乎无法在FluentNHibernate中找到它,所以甚至无法测试它是否可行。我克隆了FluentNHibernate,它似乎将release_mode设置为on_close,但这没有用。
我甚至尝试过:
public override ISession NewSession()
{
if (this.session == null)
{
if (sessionFactory == null)
{
CreateSessionFactory();
}
this.session = sessionFactory.OpenSession();
}
if (!session.IsOpen)
{
sessionFactory.OpenSession(session.Connection);
session.Connection.Open();
}
return session;
}
但它一直告诉我会议已经结束。那么,任何人都有任何建议如何处理这个?
或者这么臭,是否超出救恩?
我希望这很清楚。并原谅我的错误:我来自巴西,而不是母语为英语的人。
谢谢,
路易斯安吉洛。答案 0 :(得分:0)
我会在系统中创建CPF时检查其唯一性,并在数据库中有一个额外的唯一约束来强制执行该操作。然后,如果为CPF的每个引用设置级联为none(默认为none),则无法将新创建的重复CPF分配给实体并保存它而无异常,因此不会意外发生。
答案 1 :(得分:0)
我遇到了同样的问题。发生的事情是,内存中的SQLite将在连接关闭时删除整个架构。如果您为所有测试创建了一个会话,那么它将保留所有其他会话的结构。
有关代码和更全面的解释,请查看以下答案:Random error when testing with NHibernate on an in-Memory SQLite db