2012-11-20 18 views
0

我在內存中的Sqlite有一些麻煩。release_mode,Pooling,InMemory SQLite的最大池大小與FluentNHibernate

我有一個有CPF字段的類 - 類似於美國的SSN。作爲商業規則,CPF在系統中必須是唯一的。

所以我決定檢查這個領域的課程。現在也許有代碼味道:我檢查ORM,如果這是一個衝突CPF。

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 = "[email protected]" 
     }; 

     session.Save(client1); 
     session.Evict(client1); 
    } 

    [Then] 
    public void Motherfaker() 
    { 
     Client fromDb; 
     var clientsFromDb = session.Query<Client>() 
      .Where(c => c.eMail == "[email protected]"); 
     fromDb = clientsFromDb.FirstOrDefault<Client>(); 

     Assert.AreEqual(fromDb.FullName, "Luiz Angelo Heinzen"); 

    } 

它失敗的原因是什麼?在開始時它失敗了,因爲表格不存在。在內存中sqlite破壞每個新會話的架構。所以我改變了代碼以在NewSession()上返回同一個會話。但現在它失敗了一個NHibernate異常:Session關閉。我測試過,如果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在某種程度上它不會處理會話。我已閱讀here關於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; 
    } 

但它一直告訴我,會話關閉。那麼,任何人都有如何解決這個問題的建議?

還是這麼臭,這超出了救贖?

我希望這已經夠清楚了。並原諒我的錯誤:我來自巴西,而不是母語爲英語的人。

謝謝,

路易斯安傑洛。

回答

0

我會在系統中創建CPF時檢查唯一性,並在數據庫中有一個額外的唯一約束來強制執行此操作。然後,如果您爲CPF的每個引用設置級聯爲無(默認值爲無),則無法將新創建的重複CPF分配給實體並將其保存爲一個實例,因此不會意外發生。

0

我有同樣的問題。發生什麼情況是,當連接關閉時,內存中的SQLite將刪除整個模式。如果您創建了一個持續進行所有測試的會話,它將保留所有其他會話的結構。

有關代碼和更全面的解釋,請查看此答案:Random error when testing with NHibernate on an in-Memory SQLite db