0

メモリ内の Sqlite に問題があります。

米国の SSN に似た CPF フィールドを持つクラスがあります。ビジネス ルールとして、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 ヘルパー クラスでの実装は次のとおりです。

    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 属性については、こちらを参照してください。しかし、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;
    }

しかし、セッションが閉じられていると私に言い続けます。それで、これにアプローチする方法について何か提案はありますか?

それとも、これが救いようのないほど臭いのでしょうか?

これが十分に明確であることを願っています。私はブラジル出身で、英語のネイティブ スピーカーではありません。

ありがとう、

ルイス・アンジェロ。

4

2 に答える 2

0

私も同じ問題を抱えていました。何が起こっているかというと、接続が閉じられると、インメモリ SQLite がスキーマ全体をドロップするということです。すべてのテストで保持するセッションを作成すると、他のすべてのセッションの構造が保持されます。

コードと詳細な説明については、この回答を確認してください:インメモリ SQLite db で NHibernate をテストするときのランダム エラー

于 2012-12-02T15:04:16.327 に答える
0

システムで CPF を作成するときに一意性をチェックし、それを強制するためにデータベースに追加の Unique 制約を設定します。次に、CPF への参照ごとにカスケードを none に設定すると (デフォルトは none)、新しく作成された重複 CPF をエンティティに割り当てて例外なく保存することはできないため、誤って発生することはありません。

于 2012-11-28T14:26:26.640 に答える