NHibernate.Engine.ForeignKeys - Unable to determine if entity is transient or detached - nhibernate

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.

Related

How to persist a subset of an object instead of the whole object?

I'm struggling with a NHibernate related problem where I could use some input.
Introduction:
I have a legacy database where the relational concepts have not really been applied.
In the database I have an OrderLine table which contains data for an order lines.
On top of that the table also contains all columns with Order specific information. This could for example be order number of a customer.
E.x. If i have 10 order lines - then I have 10 rows in my OrderLines table and each row has all the Order specific data e.g. order number or customer information.
I did not want to have the above structure in my code so a view was created for Orders so that I could map my Order in NHibernate which then has a set/bag of OrderLines which makes much more sense.
Mapping: (simplified)
<class name="Order" table="[view_Orders]">
<bag name="OrderLines">
</class>
<class name="OrderLine" table="OrderLines" />
The problem:
The complexity of the view makes it impossible to save to the view. When trying NHibernates throws this exception:
NHibernate.Exceptions.GenericADOException: could not insert: XXX ---> System.Data.SqlClient.SqlException: View or function 'view_Orders' is not updatable because the modification affects multiple base tables.
My NHibernate mapping is constructed as an Order object which has a "set or bag" of OrderLine objects. Ideally I would like NHibernate only to persist the set of OrderLine objects instead of the whole object.
Is there a way of achieving this? I have tried locking the object using different lock modes but it did not help me.
You can use mutable="false" to avoid the update and deletes as this article says:
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.
To avoid the insert you can use the following statement (Uses the proyection instead an insert command, dont forget use check="none"):
<sql-insert check="none">SELECT 1</sql-insert>
Here is a tested example:
<class name="Order" table="[view_Orders]" mutable="false">
<id name="OrderId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="GrandTotal"/> -->
<set name="OrderLines" lazy="true" inverse="true" cascade="all-delete-orphan">
<key column="OrderId"/>
<one-to-many class="OrderLine"/>
</set>
<sql-insert check="none">SELECT 1</sql-insert>
</class>
<class name="OrderLine" table="OrderLine">
<id name="OrderLineId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="OrderId"/>
<property name="GrandTotal"/>/> -->
</class>
In case I do understand your issue, the solution is surprisingly simple. We just would mark root object with dynamic-update="true"
<class name="Order" table="[view_Orders]" dynamic-update="true">
...
</class>
And then apply update="false" to every property or reference which we have in that Order class mapped to view:
...
<property name="Code" update="false"/>
...
<many-to-one name="Country" update="false />
But our collection will need the standard, even cascade mapping:
<class name="Order" table="[view_Orders]" dynamic-update="true">
<bag name="OrderLines"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
...
</bag>
... // other stuff is update="false"
</class>
And now code like this would do management of OrderLines, while not executing any updates on the root object Order
var session = ... // get ISession
// load root
var root = session.Get<Order>(123);
// if needed change existing line (pretend there is one)
root.OrderLines[0].Amount = 100;
// add new
var newOrder = ... // new order
root.OrderLines.Add(newOrder);
session.Save(root);
session.Flush();
And that is it. Cascade on the root object is doing what we need, while the update="false" is not updating it...
NOTE: Just interesting note - there is also class and collection
setting mutable="false", but it would not work here... as the
solution mentioned above (it is sad, because that would be more
elegant, but not working as expected...). See:
19.2.2. Strategy: read only
If your application needs to read but never modify instances of a persistent class, a read-only cache may be used. This is the simplest and best performing strategy. Its even perfectly safe for use in a cluster.
<class name="Eg.Immutable" mutable="false">

Nhibernate Cannot delete the child object

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

"Invalid Index n for this SqlParameterCollection with Count=n" OR "foreign key cannot be null"

I have been successfully using NHibernate for quite some time now and
have been able to solve a lot of pitfalls with an application that I
developed with it and that is running in production. The recent hurdle
really has me scratching my head, though.
Recently I had to expand the class library with some new classes that
are nested as children to some already existing classes. I just copied
the same model for aggregate mapping that I already was successfully
using, but this time it does not work.
Now when I use the following in the parent mapping file:
<bag name="SeaInfoItems" table="EDIImport_SeaInfo" lazy="false" cascade="save-update">
<key column="EDI_FK_OWNERID"/>
<one-to-many class="FargoGate.AppLib.EdiImportSeaInfo, FargoGate.AppLib"/>
</bag>
I can choose to, in the child class, either use:
<property name="EDI_FK_OWNERID" column="EDI_FK_OWNERID" />
...which gives me the infamous "Invalid Index n for this
SqlParameterCollection with Count=n" error.
OR I try with this solution I found after some Googling:
<property name="EDI_FK_OWNERID" column="EDI_FK_OWNERID" insert="false" update="false" />
...which gives me a "Cannot insert the value NULL into column
'EDI_FK_OWNERID'... column does not allow nulls." error.
So basically I have to choose between pest and cholera.
What I don't get is that it works flawlessly for the already existing
aggregate classes, and I really cannot spot the difference. The only
thing is that this foreign key (EDI_FK_OWNERID) could refer to two
different parent tables. Bad database design, I know, but I didn't
design it, and it is my task to develop up to it for better or worse. I cannot change the database design.
The other difference is that I totally removed the foreign key reference from the already existing child classes (the mappings as well as the class members). I tried to emulate that of course, but of no avail.
Also I discovered that one of the new classes (which is quite small) also works fine. But I cannot see what the difference is here either. I am stumped!
Anyone has a clue?
Aaargh! I was put so much on a wrong leg with this infamous “Invalid Index n for this SqlParameterCollection with Count=n” error that I overlooked the obvious: A duplicate mapping of a field for ONE of the classes.
In that particular mapping I left this error, where the primary key is also defined as a property:
<id name="ID" column="ID">
<generator class="guid" />
</id>
<property name="ID" column="ID" />
Now that was a waste of time trying to debug that!

Nhibernate mapping issue: a property whose type is a superclass

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.

What would cause NHibernate to return an invalid identity selection when using JET?

Our application (sadly) uses an MDB back-end database (I.e. JET engine).
One of the items being persisted to the database is an "event" object. The object is persisted to a table with an ID (EventLogID) that is an Autonumber field. The NHibernate mapping is as follows:
<class name="EventLogEntry" table="tblEventLog" proxy="IEventLogEntry">
<id name="Id">
<column name="EventLogID" not-null="true" />
<generator class="native" />
</id>
<property name="Source" column="ErrorLogSource" />
<property name="Text" column="EventLogText" />
<property name="Time" column="EventLogTime" />
<property name="User" column="UserID" />
<property name="Device" column="EventDeviceID" />
</class>
According to the log file, on some occasions when NHibernate attempts to obtain the identity, it receives the value "0". Later, when Flush is called, NHibernate suffers from an assertion failure.
Can anyone suggest why this might be happening? Better yet, can anyone suggest how to fix it?
Regards,
Richard
It could be that the default 'connection-release-mode' configuration setting is the cause of the problems.
A while ago, I ran into a similar issue, and I found that changing the connection.release-mode to 'on_close' (instead of the default after_transaction) solved the issue.
More information can be found on my blog
edit: as I'm thinking of it, perhaps it can be solved without changing the release-mode as well; what happens if you use a transaction to save your event ?
The default release-mode is after transaction, so I'm thinking; perhaps when you use an explicit transaction, the connection will only be closed after the transaction. The question offcourse is, will NHibernate try to retrieve the primary key that has been given to the object inside this transaction, or will it use another transaction ...
If it does not work, then changing the release-mode will solve your problem as well, but it is maybe not the best option.
I think the best option/solution, is to use an explicit transaction first, and see if this solves the problem...