I'm trying to bulk-update entities using a StatelessSession.
Because it's stateless, NHibernate doesn't auto-cascade child entities upon save.
This is fine because I don't want to make any changes to any of the child entities.
Unfortunately, upon save, NHibernate complains:
"object references an unsaved transient instance - save the transient instance before flushing. Type: MyAssembly.MyRandomEntity, Entity: Castle.Proxies.MyRandomEntityProxy"
Of course if I try and update the child entity, I get the error:
"No persister for: Castle.Proxies.MyRandomEntityProxy"
As you can see, the child entity is a proxy because it hasn't been loaded. I don't need it, I don't want to update it... but even if I did I'm not sure how I could.
Any idea how to solve this problem, basically telling it to ignore the transient child entities?
Update
Here is the mapping for the child entity on the parent object:
<many-to-one class="MyAssembly.Flight, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="OutboundFlight">
<column name="OutboundFlightId" />
</many-to-one>
Here is the Id column on the child entity:
<id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
<column name="FlightId" />
<generator class="assigned" />
</id>
its using the assigned generator which uses 'unsavedvalue' to know if the instance is peristent or transient. Maybe there really is an Flightobject with id = 0 in the database? Then it would be created as a proxy with Id = 0 which would be treated as transient instance.
Related
I have this Instrument entity:
<class name="Instrument" table="Instruments" mutable="false">
<id name="ID" column="INSTRUMENT_ID" unsaved-value="0">
<generator class="assigned" />
</id>
<property name="....." />
<property name="....." />
</class>
This entity is used in many-to-one relationship in other entity (InstrumentSelection). This is many-to-one mapping info:
<many-to-one name="Instrument" access="field.camelcase" column="Instrument_ID" update="false" class="Instrument" not-null="true" fetch="join" lazy="false" />
The issue I've it that when I save InstrumentSelection entity with Save:
Transact(() => session.Save(entity));
I get error in logs:
2012-12-20 14:09:54,607 WARN 12 NHibernate.Engine.ForeignKeys - Unable
to determine if Instrument with assigned
identifier 11457 is transient or detached; querying the database. Use
explicit Save() or Update() in session to prevent this.
A few facts about Instrument entity:
It's just a reference entity
It's immutable entity
It can not be added / inserted via application. I get rows in database from external feed.
Question (version 1): A my question is: is there a way to instruct NHibernate to always consider Instrument entity as detached? I mean - if an instance of Instrument exists in application it means that it's present in database. So there is no too much sense in quering the database.
EDIT 1: Because Question (version 1) was not answered yet, let me change it slightly:
Question (version 2): What could be the behaviour that NHibernate is still trying to work out whether entity is detached/transient? I think I have my mapping configured correctly (unsaved-value, generator).
The problem is that when you save the InstrumentSelection, NHibernate is cascading the operation to save the child Instruments. My first suggestion is to set cascade to none on the InstrumentSelect side of the relationship.
My second suggestion is to use an interceptor as shown in this answer.
I know it has been asked for many times, i also have found a lot of answers on this website, but i just cannot get out this problem.
Can anyone help me with this piece of code?
Many thanks.
Here is my parent mapping file
<set name="ProductPictureList" table="[ProductPicture]" lazy="true" order-by="DateCreated" inverse="true" cascade="all-delete-orphan" >
<key column="ProductID"/>
<one-to-many class="ProductPicture"/>
</set>
Here is my child mapping file
<class name="ProductPicture" table="[ProductPicture]" lazy="true">
<id name="ProductPictureID">
<generator class="identity" />
</id>
<property name="ProductID" type="Int32"></property>
<property name="PictureName" type="String"></property>
<property name="DateCreated" type="DateTime"></property>
</class>
Here is my c# code
var item = _productRepository.Get(productID);
var productPictrue = item.ProductPictureList
.OfType<ProductPicture>()
.Where(x => x.ProductPictureID == productPictureID);
// reomve the finding item
var ok = item.ProductPictureList.Remove(productPictrue);
_productRepository.SaveOrUpdate(item);
ok is false value and this child object is still in my database.
Not 100% sure, but could be because you have defined ProductID as a property of ProductPicture, I assume this is the PK from the Product class. You don't need to add this again, it will be created by the relationship.
I'm not sure that your use of table="[ProductPicture]" in the set tag is right.
The one-to-many tag already establishes the link between ProductPictureList and ProductPicture.
I think the table attribute is generally for using a separate relationship table when modelling many-to-may relationships.
From nhibernate.info Doc:
table (optional - defaults to property name) the name of the
collection table (not used for one-to-many associations)
And:
A collection table is required for any collection of values and any
collection of references to other entities mapped as a many-to-many
association
I'm attempting to use NHibernate to serialize a moderately complex object graph*
Actual mapping was done via FNH, but I've dumped the HBM files and confirmed that the generated XML conforms to NHibernate conventions.
Here's a snippet of the HBM, just for grins:
<class xmlns="urn:nhibernate-mapping-2.2" schema="obsv" optimistic-lock="version" name="Spc.Ofp.Tubs.DAL.Entities.PurseSeineActivity, TubsDAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="s_daylog">
<id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="s_daylog_id" not-null="true" />
<generator class="identity" />
</id>
This mapping results in the following SQL (via SQL debug, snipped for readability):
INSERT INTO obsv.s_daylog (/* columns 0 thru 20 snipped */s_daylog_id /* <-- PK from mapping! */)
VALUES (/* parameters snipped */#p21);
select SCOPE_IDENTITY();#p21 = NULL [Type: Int32 (0)]
I believe that the presence of the "select SCOPE_IDENTITY();" text confirms that
NHibernate partially understands what should happen. I just don't understand why it's writing the PK column into the insert query.
I've been using the mappings for reading the graph just fine, so I'm fairly certain this isn't a basic mapping issue.
FWIW, Cascade is set to None (for other reasons, I need to work with these entities without
ramifications up and down the object graph).
*By moderately complex, I mean I have a object which has between 6 and 10 properties which are lists of child entities. A good number of those child entities also have child entities. In the most complex case, there are 5 generations of entities under the root entity.
I think it is because your mapping seems incorrect.
According to the NHibernate Reference, the id tag has a "column" attribute to set the column name, not a child element.
Try using dynamic-insert="true":
<class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true" schema="obsv" optimistic-lock="version" name="Spc.Ofp.Tubs.DAL.Entities.PurseSeineActivity, TubsDAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="s_daylog">
I have an NHibernate object that is a superclass (let's call it "Super"), and a subclass that inherits from it (let's say it's called "Sub").
<class name="Super" table="SuperThings">
<id name="Id" type="System.Int32" column="SuperId">
<generator class="identity" />
</id>
<joined-subclass name="Sub" table="SubThings" extends="Super" lazy="true">
<key column="SubId" />
</joined-subclass>
</class>
I have a separate class (called "Widget") with a property of type Super.
<class name="Widget" table="Widgets" lazy="true">
<id name="Id" type="System.Int32" column="NoteId">
<generator class="identity" />
</id>
<many-to-one name="SuperProperty" column="SuperId" class="SuperClass" />
</class>
When I access SuperProperty on an instance of a Widget, NHibernate attempts to lazily load it, but I get this error:
More than one row with the given identifier was found: 1, for class: Super
There is only one record in SuperThings with an id of 1, and a separate record in SubThings associated to it. After using the NHibernate Profiler and debugging my code, it looks like NHibernate is trying to instantiate an object whose type is the subclass.
Why is it doing that? Is there something wrong with how I'm thinking this should be mapped?
Obviously, this is a simplified version of what I'm actually working with. The objects I'm working with have many more properties of different types, so maybe I've left out what's actually causing the problem, but I wanted to make sure that I'm understanding things on a basic level at least.
If there is a record in SuperThings with Id=1, and one record in SubThings with SubId=1, according to your mapping you have a Sub instance persisted, so NHibernate is right when it tries to instantiate it.
If this is not what you intended, you should reread Chapter 8. Inheritance Mapping to see the alternatives.
I Have one-to-one relation in my NHibernate mapping:
<many-to-one name="PersonProfile" not-null="true"
class="PersonProfile" column="profile" cascade="all" lazy="proxy"/>
...
<one-to-one name="Owner" class="Person" property-ref="PersonProfile"
constrained="true" lazy="proxy"/>
PersonProfile class have batch-size attribute set. When user.PersonProfile property is hit batch load triggers. But then, when Owner property is loaded it loads from database. Why?
Because one-to-one relations can not be lazy loaded (in some circumstances).
See this fine explanation: NHibernate: how to enable lazy loading on one-to-one mapping