1
votes

I have read many questions and answers, but I couldn´t find solution for my problem. The problem occurs when I migrated from NHibernate 1.2.1 to 2.1.2. I have this common error:

object references an unsaved transient instance - save the transient instance before flushing. Type: Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion, Entity: Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion

NHibernate configuration:
&ltnhibernate>
          &ltadd key="hibernate.show_sql" value="true" />
          &ltadd key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
          &ltadd key="dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
          &ltadd key="proxyfactory.factory_class" value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" />
          &ltadd key="driver_class" value="NHibernate.Driver.SqlClientDriver" />
          &ltadd key="connection.connection_string" value="..." />          
&lt/nhibernate>

The mapping of main class CRResidence:

&lt?xml version="1.0" encoding="utf-8" ?> 
&lthibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
&ltclass name="Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidence, Mikro.FareOn.Modules.Cards.Interface" table="CR_Residence">
    &ltid name="Id" column="id" type="Int64" access="nosetter.camelcase" unsaved-value="0">
      &ltgenerator class="identity" />
    &lt/id>
    &ltversion name="VersionId" column="version_id" type="Int64" />
    &ltproperty name="IsDeleted" column="deleted" type ="Boolean" not-null="true" />
    &ltproperty name="Name" column="name" type="String" not-null="true" />
    &ltmany-to-one name="Region" column="region_id" cascade="none" class="Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion, Mikro.FareOn.Modules.Cards.Interface"/>
    &ltproperty name="Postcode" column="postcode" type="String" not-null="true" />
    &ltmany-to-one name="Country" column="residence_country_id" cascade="none" class="Mikro.FareOn.TransportOperator.Interface.BEC.TOResidenceCountry, Mikro.FareOn.TransportOperator.Interface"/>
  &lt/class>
&lt/hibernate-mapping> 

And one of the class in relation many-to-one:

&lt?xml version="1.0" encoding="utf-8" ?> 
&lthibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  &ltclass name="Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion, Mikro.FareOn.Modules.Cards.Interface" table="CR_ResidenceRegion" >
    &ltid name="Id" column="id" type="Int64" access="nosetter.camelcase" unsaved-value="0">
      &ltgenerator class="identity" />
    &lt/id>
    &ltversion name="VersionId" column="version_id" type="Int64" />
    &ltproperty name="Name" column="name" type="String" not-null="true" />
    &ltproperty name="IsDeleted" column="deleted" type ="Boolean" not-null="true" />
  &lt/class>
&lt/hibernate-mapping>

Implementation of class CRResidenceRegion:

[Serializable]
    public class CRResidence : BussinesEntityComponentBase //this is class, which implements Equals and define Id, VersionId, IsDeleted
    {
    string name;
        string postcode;
    CRResidenceRegion region;
    TOResidenceCountry country;

    #region Getters/Setters

    /// 
    /// Nazev mista
    /// 
    public string Name
    {
      get { return this.name; }
      set { this.name = value; }
    }
    /// 
    /// Region
    /// 
    public CRResidenceRegion Region
    {
      get
      {
        return this.region;
      }
      set
      {
        this.region = value;
      }
    }
    /// 
    /// Stát
    /// 
    public TOResidenceCountry Country
    {
      get
      {
        return this.country;
      }
      set
      {
        this.country = value;
      }
    }
    /// 
    /// PSC
    /// 
    public string Postcode
    {
      get { return this.postcode; }
      set { this.postcode = value; }
    }
    public string PostcodeAndName
    {
      get { return String.Format("{0} - {1}", Postcode, Name); }
    }
    public string NameAndPostcode
    {
      get { return String.Format("{1} - {0}", Postcode, Name); }
    }
    #endregion
    /// 
    /// Konstruktor objektu rezidence
    /// 
    public CRResidence()
      : base()
    {
    }    
}

I have tried all types of cascades, but any cascade doesn't work correctly. But for my occasion I prefer cascade = "none". I have the client side, where I load the object CRResidenceRegion by calling method on server side in one NHibernate session. After loading the NHibernate session is closed. Object on client is correct, correct Id from database and so on. Then to the CRResidence object is assigned CRResidenceRegion object. Then it is called method on server side:

using (PersistenceSession session = Registrator.OpenSession())
{
        ITransaction trx = session.BeginTransaction();
        try
        {          
          session.Update(residence);
          //residence.Region = (CRResidenceRegion)session.Get(typeof(CRResidenceRegion), residence.Region.Id);    
          //residence.Country = (TOResidenceCountry)session.Get(typeof(TOResidenceCountry), residence.Country.Id);
          trx.Commit();
          log.Debug("CRResidence updated.");
          return residence;
        }
        catch (Exception ex)
............
      }

I have many objects like this, this problem appered when I migrated to NHibernate 2.1.2. In some occasions works fine after define cascade style ("none" worked as well as "all", where I needed). Could be problem in configuration file of NHibernate.

Previous definition of the problem: When I try to insert or update instance of CRResidence, the error about unsaved transient error occurs. Instance of CRResidenceRegion is completely initialized, including Id, so there is no problem. I have implemented Equal method on Id. I have tried to clear cache, but it wasn't helpful. When I change cascade to save-update, it works, but records of CRResidenceRegion are duplicated. One solution is that I read CRResidenceRegion from database in same session (commented in code below) before I save CRResidence, but this is not acceptable.

It seems that NHibernate has propably lost reference to CRResidenceRegion and thinks that it is new created, but it's not.

3

3 Answers

1
votes

Use the Session.Load method instead of Get to initialize the CRResidenceRegion entity. This won't actually go to the database unless you access any of its properties.

...
residence.Region = session.Load<CRResidenceRegion>(residence.Region.Id);         
session.Update(residence);
trx.Commit();
...
0
votes

This might be because it came from another ession.

Try session.Merge() instead.

0
votes

I have found the solution of my problem. Problem was in version_id, I have added a unsaved-value to mapping file of CR_ResidenceRegion.

&ltversion name="VersionId" column="version_id" type="Int64" unsaved-value="0" />

I think they changed the default value of unsaved-value.

Thanks everyone for help