NHibernate 2.1.2 未保存的瞬态实例
我已阅读许多问题和答案,但找不到解决我的问题的方法。当我从 NHibernate 1.2.1 迁移到 2.1.2 时,出现了这个问题。 我有一个常见错误:
对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例。类型:Mikro.FareOn.Modules.Cards.Interface.BEC.CRResidenceRegion,实体: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>
主类 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>
与多对一关系的类之一:
<?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>
类 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() { } }
我尝试了所有类型的级联,但任何级联都无法正常工作。但就我而言,我更喜欢cascade =“none”。 我有客户端,通过在一个 NHibernate 会话中调用服务器端的方法来加载对象 CRResidenceRegion。加载后,NHibernate 会话关闭。客户端上的对象是正确的,数据库中的 ID 是正确的等等。然后给CRResidence对象分配CRResidenceRegion对象。 然后在服务器端调用方法:
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) ............ }
我有很多这样的对象,当我迁移到NHibernate 2.1.2时出现这个问题。在某些情况下,定义级联样式后效果很好(在我需要的地方,“无”和“全部”一样有效)。可能是NHibernate的配置文件有问题。
问题的先前定义: 当我尝试插入或更新 CRResidence 实例时,出现有关未保存瞬态错误的错误。 CRResidenceRegion的实例已经完全初始化,包括Id,所以没有问题。我已经在 Id 上实现了 Equal 方法。我曾尝试清除缓存,但没有帮助。当我将级联更改为保存更新时,它可以工作,但 CRResidenceRegion 的记录是重复的。一种解决方案是,在保存 CRResidence 之前,我在同一会话中从数据库读取 CRResidenceRegion(在下面的代码中注释),但这是不可接受的。
NHibernate 似乎已经丢失了对 CRResidenceRegion 的引用,并认为它是新创建的,但事实并非如此。
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 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 Session.Load 方法而不是 Get 来初始化 CRResidenceRegion 实体。除非您访问数据库的任何属性,否则它实际上不会进入数据库。
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.
这可能是因为它来自另一个会话。
请尝试使用
session.Merge()
来代替。This might be because it came from another ession.
Try
session.Merge()
instead.我已经找到了我的问题的解决方案。
问题出在 version_id 中,我已将未保存的值添加到 CR_ResidenceRegion 的映射文件中。
我认为他们更改了未保存值的默认值。
谢谢大家的帮助
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.
I think they changed the default value of unsaved-value.
Thanks everyone for help