开发者

NHibernate 2.1.2 unsaved transient instance

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:
<nhibernate>
          <add key="hibernate.show_sql" value="true" />
          <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
          <add key="dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
          <add key="proxyfactory.factory_class" value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" />
          <add key="driver_class" value="NHibernate.Driver.SqlClientDriver" />
          <add key="connection.connection_string" value="..." />          
</nhibernate>

The mapping of main class CRResidence:

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

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

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  <class name="Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion, Mikro.FareOn.Modules.Cards.Interface" table="CR_ResidenceRegion" >
    <id name="Id" column="id" type="Int64" access="nosetter.camelcase" unsaved-value="0">
      <generator class="identity" />
    </id>
    <version name="VersionId" column="version_id" type="Int64" />
    <property name="Name" column="name" type="String" not-null="true" />
    <property name="IsDeleted" column="deleted" type ="Boolean" not-null="true" />
  </class>
</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 clie开发者_运维知识库nt 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.


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();
...


This might be because it came from another ession.

Try session.Merge() instead.


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.

<version name="VersionId" column="version_id" type="Int64" unsaved-value="0" />

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

Thanks everyone for help

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜