使用FluentNHibernate的InMemory SQLite的release_mode,Pooling,Max Pool大小

时间:2012-11-20 17:23:46

标签: sqlite fluent-nhibernate in-memory-database

我在内存中遇到了一些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异常而失败:会话已关闭。我已经测试了,如果从这个

更改find​​ByCpfNumber
    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;
    }

但它一直告诉我会议已经结束。那么,任何人都有任何建议如何处理这个?

或者这么臭,是否超出救恩?

我希望这很清楚。并原谅我的错误:我来自巴西,而不是母语为英语的人。

谢谢,

路易斯安吉洛。

2 个答案:

答案 0 :(得分:0)

我会在系统中创建CPF时检查其唯一性,并在数据库中有一个额外的唯一约束来强制执行该操作。然后,如果为CPF的每个引用设置级联为none(默认为none),则无法将新创建的重复CPF分配给实体并保存它而无异常,因此不会意外发生。

答案 1 :(得分:0)

我遇到了同样的问题。发生的事情是,内存中的SQLite将在连接关闭时删除整个架构。如果您为所有测试创建了一个会话,那么它将保留所有其他会话的结构。

有关代码和更全面的解释,请查看以下答案:Random error when testing with NHibernate on an in-Memory SQLite db