2017-06-29 6 views
0

Tout en essayant de sauver un objet avec ses enfants, NHibernate jettetransaction NHibernate commit ou rollback pour un graphe d'objet lance « ObjectDisposedException »

System.ObjectDisposedException: 'Cannot access a disposed object.' 

lorsque le tx.Commit() est appelé.

Étrangement, les données sont toujours conservées dans les tables de base de données.

Ma session NHibernate est liée à la demande web via

if (!CurrentSessionContext.HasBind(sessionFactory)) 
     CurrentSessionContext.Bind(sessionFactory.OpenSession()); 

J'utilise ASP.NET MVC 5, NHibernate 4.1, (Ne pas utiliser Fluent NHibernate bien)

est Ci-dessous le code qui produit l'erreur:

code:

ISession session = SessionFactory.GetCurrentSession();    
    session.SetBatchSize(1000); 
    using (var tx = session.BeginTransaction()) 
    { 
     try 
     { 
      IList<Bar> barList = session.QueryOver<Bar>().Where(b => b.IsEnabled == true).List(); 

      foreach (Bar bar in barList) 
      { 
       var foo = new Foo { BarObj = bar }; 

       foo.BarDetailList = new HashSet<BarDetail>(); 
       foreach (Alpha alpha in bar.AlphaList) 
       { 
        foreach (Beta beta in alpha.BetaList) 
        { 
         foo.BarDetailList.Add(
          new BarDetail { ParentFoo = foo, AlphaObj = alpha, BetaObj = beta } 
         ); 
        } 
       } 

       session.Persist(foo); // Save gives same result 
      } 
      tx.Commit(); // This line throws the ObjectDisposedException 
     } 
     catch (Exception ex) 
     { 
      // details omitted 
      tx.Rollback(); 
     } 
    } 

Définitions de classe:

public class BarDetail : AuditableModelBase 
{ 
    public virtual Foo ParentFoo { get; set; } 
    public virtual Alpha alpha { get; set; } 
    public virtual Beta beta { get; set; } 
    public virtual IList<BarMonthlyDetail> MonthlyDetailList { get; set; } 
    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var barDetail = obj as BarDetail; 
     if (barDetail == null) 
      return false; 

     if (barDetail.Id.HasValue && barDetail.Id == this.Id) 
      return true; 
     else 
     { 
      // If id is null, then look for other members used when adding 
      // BarDetail objects as child objects at the time of creation of forecast 
      // otherwise they wont get added 
      if (this.alpha != null && barDetail.alpha != null && this.alpha.Id == barDetail.alpha.Id 
       && this.beta != null && barDetail.beta != null && this.beta.Id == barDetail.beta.Id) 
       return true; 

     } 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class BarMonthlyDetail : AuditableModelBase 
{ 
    public virtual BarDetail ParentBarDetail { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var barMonthlyDetail = obj as BarMonthlyDetail; 
     if (barMonthlyDetail == null) 
      return false; 

     if (barMonthlyDetail.Id == this.Id) 
      return true; 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class Bar : AuditableModelBase 
{ 
    public Bar() 
    { 
    } 

    public virtual ISet<UserAccount> Users { get; set; } 
    public virtual ISet<Alpha> alphas { get; set; } 
    public virtual ISet<Beta> betas { get; set; } 

    public override string ToString() 
    { 
     return Name ?? ""; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var bar = obj as Bar; 
     if (bar == null) 
      return false; 

     if (bar.Id == this.Id) 
      return true; 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      //hash = hash * 23 + (Name ?? "").GetHashCode(); 
      //hash = hash * 23 + (Code ?? "").GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class Foo : AuditableModelBase 
{   
    public virtual Bar bar { get; set; } 
    public virtual IList<BarDetail> BarDetailList { get; set; } 

    public override string ToString() 
    { 
     return Name ?? ""; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var foo = obj as Foo; 
     if (foo == null) 
      return false; 

     if (foo.Id == this.Id) 
      return true; 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class Alpha : AuditableModelBase 
{ 
    public virtual ISet<Bar> bars { get; set; } 
    public virtual ISet<Beta> betas { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var alpha = obj as Alpha; 
     if (alpha == null) 
      return false; 

     if (alpha.Id == this.Id) 
      return true; 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class Beta : AuditableModelBase 
{ 

    public virtual Bar bar { get; set; } 
    public virtual Alpha alpha { get; set; } 

    public override string ToString() 
    { 
     return Name ?? ""; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 

     var beta = obj as Beta; 
     if (beta == null) 
      return false; 

     if (beta.Id == this.Id) 
      return true; 

     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + Id.GetHashCode(); 
      return hash; 
     } 
    } 
} 

Mappages:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="BarDetail" table="BarDetail"> 
    <id name="Id"> 
     <generator class="identity"/> 
    </id> 
    <property name="IsEnabled" not-null="true"/> 
    <many-to-one name="ParentFoo" class="Foo" column="FooId" not-null="true"/> 
    <many-to-one name="alpha" class="Alpha" column="AlphaId" not-null="true"/> 
    <many-to-one name="beta" class="Beta" column="BetaId" not-null="true"/>  
    <bag name="MonthlyDetailList" table="BarMonthlyDetail" lazy="true" cascade="save-update" order-by="Month asc" > 
     <key> 
     <column name="BarDetailId" not-null="true"/> 
     </key> 
     <one-to-many class="BarMonthlyDetail"/> 
    </bag> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="BarMonthlyDetail" table="BarMonthlyDetail"> 
    <id name="Id"> 
     <generator class="identity"/> 
    </id> 
    <property name="Month" /> 
    <many-to-one name="ParentBarDetail" class="BarDetail" column="BarDetailId" not-null="true"/> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="Foo" table="Foo"> 

    <id name="Id"> 
     <generator class="identity"/> 
    </id> 

    <many-to-one name="bar" class="Bar" column="BarId" not-null="true"/> 

    <bag name="BarDetailList" table="BarDetail" lazy="true" cascade="save-update"> 
     <key> 
     <column name="FooId" not-null="true"/> 
     </key> 
     <one-to-many class="BarDetail"/> 
    </bag> 

    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="Beta" table="Beta"> 
    <id name="Id"> 
     <generator class="identity" /> 
    </id> 
    <property name="IsEnabled" not-null="true"/> 
    <many-to-one name="bar" class="Bar" column="BarId" not-null="true" /> 
    <many-to-one name="alpha" class="Alpha" column="AlphaId" not-null="true" /> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="Alpha" table="Alpha"> 
    <id name="Id"> 
     <generator class="identity" /> 
    </id> 
    <set name="alphas" table="AlphaBar" lazy="true"> 
     <key column="AlphaId" not-null="true"/> 
     <many-to-many class="Bar" column="BarId"/> 
    </set> 
    <set name="betas" table="Beta" lazy="true" inverse="true"> 
     <key column="BarId" not-null="true"/> 
     <one-to-many class="Beta" /> 
    </set> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="DataAccess.Models"> 
    <class name="Bar" table="Bar"> 
    <id name="Id"> 
     <generator class="identity" /> 
    </id> 
    <set name="Users" table="UserBar" inverse="true" lazy="true"> 
     <key column="BarId"/> 
     <many-to-many class="UserAccount" column="UserId"/> 
    </set> 
    <set name="alphas" table="AlphaBar" inverse="true" lazy="true"> 
     <key column="BarId"/> 
     <many-to-many class="Alpha" column="AlphaId"/> 
    </set> 
    <set name="betas" table="Beta" lazy="true" inverse="true"> 
     <key column="BarId" not-null="true"/> 
     <one-to-many class="Bar" /> 
    </set> 
    </class> 
</hibernate-mapping> 

j'ai essayé de chercher des semblables SO messages (par exemple This) et ou sur le Web, mais ce problème semble être différent

Mise à jour: J'ai aussi essayé en réglant le mode flush explicitement session.FlushMode = FlushMode.Commit; précédemment, il a été mis à Auto mais l'erreur persiste

+0

Votre 'try catch' est inutile et même dangereux (exception swallow). Le 'using 'est suffisant. Si elle n'est pas validée, la transaction sera annulée. Vous cachez peut-être l'erreur réelle avec. Essayez à nouveau sans. –

+0

Le code inutile est découpé dans le bloc 'catch'. Je fais de la journalisation et, dans certains cas, je convertis l'exception en une autre. J'ai mis à jour le bloc catch. –

+0

Etes-vous sûr que votre 'ObjectDisposedException' ne provient pas de votre bloc catch? Vous n'avez pas inclus la trace de la pile, vous n'avez pas dit quelle ligne la lançait. –

Répondre

0

je me suis débarrassé de l'erreur . J'utilisais un Set quand je l'ai changé en Bag et basé ma méthode GetHashCode() seulement sur Id, il a commencé à fonctionner correctement.

+0

Dans la plupart des cas 'set' mieux modélise vos données que' bag', mieux vaut le garder. Donc, mieux trouver la cause réelle de votre problème. Pourquoi 'GetHashcode' était-il basé sur autre chose que' Id'? C'est suspect. C'est une erreur si ces autres choses sont mutables. Un hashcode ne doit pas changer une fois calculé. –

+0

Convenu. Mais qu'en est-il de l'ajout de plusieurs objets en même temps? 'foo.BarDetailList' ne peut pas ajouter plusieurs nouveaux objets' GetHashCode' est juste basé sur l'Id de l'objet.Avez-vous une meilleure solution dans cette situation? –

+0

Il n'y a aucune raison qu'un ensemble refuse de recevoir de nombreux objets différents. Il doit y avoir un autre problème dans votre code. Ce que vous montrez dans votre question n'est pas un [mcve], je ne pense pas que quiconque puisse reproduire votre problème et le trier actuellement. Essayez de fournir un [mcve]. –