NHibernate removing FK in one-to-many association on update - nhibernate

First, here is my relation
<class name="ServiceStep">
<id name="Id">
<generator class="guid.comb"/>
</id>
<set name="AdditionalInfoRows" cascade="save-update" >
<key column="ServiceStepId"/>
<one-to-many class="AdditionalInfoRow"/>
</set>
<class name="AdditionalInfoRow">
<id name="Id">
<generator class="guid.comb"/>
</id>
<set name="AdditionalInfos" cascade="save-update" >
<key column="AdditionInfoRowId"/>
<one-to-many class="AdditionalInfo"/>
</set>
Now, when I create new ServiceStep and add AdditionalInfoRows into it, everything works fine and it's correctly persisted.
The problem is by update. I load ServiceStep and the Set is correctly loaded with AdditionalInfoRows. In my application I add new AdditionalInfoRows to this set. Then I call SaveOrUpdate on ServiceStep. Newly addes AdditionalInfoRows are persisted correctly but my original list looses the connection. FK in AdditionalInfoRows which should point to ServiceStep is set to NULL by NHibernate.
Hope somebody can point me into right direction.

You can try including something like this in your AdditionalInfoRow mapping:
<many-to-one name="ServiceStep" class="ServiceStep">
<column name="ServiceStepId" not-null="true"/>
</many-to-one>
to look like,
<class name="AdditionalInfoRow">
<id name="Id">
<generator class="guid.comb"/>
</id>
<set name="AdditionalInfos" cascade="save-update" >
<key column="AdditionInfoRowId"/>
<one-to-many class="AdditionalInfo"/>
</set>
<many-to-one name="ServiceStep" class="ServiceStep">
<column name="ServiceStepId" not-null="true"/>
</many-to-one>
</class>

Related

NHibernate WARNING and the data is not saved

While I am saving by calling SaveOrUpdate(), I got this warning and the data is not saving in the database after calling Transaction.Commit().
NHibernate.Engine.ForeignKeys - Unable
to determine if [project name] with
assigned identifier [primarykey] is
transient or detached; querying the
database. Use explicit Save() or
Update() in session to prevent this.
I am inserting a new object. Google search tell me to call Save() instead of SaveOrUpdate(): means Save() is only for inserting.
I search in Google and do not see much about this.
Could anyone give me suggestion for this problem or this warning?
Edit:
Here is the simulated sample mapping files -
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly=""
namespace="">
<class name="Customer" table="[dbo].[Customer]" optimistic-lock="none" >
<id name="CustomerId" column="CustomerId" >
<generator class="assigned"/>
</id>
<property name="Name" column="Name" />
<property name="Age" column="Age" />
<set name="CustomerDetails" cascade="none" inverse="true" fetch="select">
<key>
<column name="CustomerId"/>
</key>
<one-to-many class="CustomerDetail"/>
</set>
<many-to-one name="MGender" fetch="select" cascade="none">
<column name="GenderCode"/>
</many-to-one>
</class>
</hibernate-mapping>
<class name="CustomerDetails" table="[dbo].[CustomerDetail]" optimistic-lock="none" >
<id name="CustomerDetailId" column="CustomerDetailId" >
<generator class="assigned"/>
</id>
<property name="Detail1" column="Detail1" />
<many-to-one name="Customer" fetch="select" cascade="none">
<column name="CustomerId"/>
</many-to-one>
</class>
<class name="MGender" table="[dbo].[MGender]" optimistic-lock="none" >
<id name="GenderCode" column="GenderCode" >
<generator class="assigned"/>
</id>
<property name="Description" column="Description" />
<set name="Customers" cascade="none" inverse="true" fetch="select">
<key>
<column name="GenderCode"/>
</key>
<one-to-many class="Customer"/>
</set>
</class>
You're using an assigned identifier so you need to set the unsaved-value attribute so that NHibernate can determine if an entity should be inserted or updated. Or you can explicitly call Save for new entities.
<id name="CustomerId" column="CustomerId" unsaved-value="???" >
<generator class="assigned"/>
</id>
Please note that if you are using a custom id, ie not using Id(x => x.Id).GeneratedBy.Assigned() and you do not have any version or timestamp columns, there is no way NHibernate would know if thuis is a new row or an existing one. So, I fixed my problem by using GeneratedBy.UuidString(). Works like a charm. Almost put my code into production with this error message, fortunately my information was being saved.

nhibernate : mapping to column other than primary key

I have the following map. My intention is for the order.BasketId to map to orderItem.BasketId. Tho when i look at the sql i see that it's mapping
order.Id to orderItem.BasketId. How do i define in my order map which order property to map against basketId. It seems to default to the primary key.
<class name="Order" table="Orders">
<id name="Id" type="Int32" column="Order_ID" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="BasketId" column="Basket_ID" type="Int32"/>
<set name="OrderItems" table="item_basket_contents" generic="true" inverse="true" >
<key column="Basket_ID" />
<one-to-many class="EStore.Domain.Model.OrderItem, EStore.Domain"/>
</set>
</class>
and orderItem
<class name="OrderItem" table="Item_Basket_Contents">
<id name="Id" type="Int32" column="ID" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="BasketId" column="Basket_ID" type="Int32"/>
</class>
Use the following:
<key column="Basket_ID" property-ref="BasketId" />
That's it.
Can you change the structure? I would have a Basket entity, which contains the order items. Your order then refers to this basket, and the basket contains the items. The explicit basketID in Order is circumventing some of the ORM that hibernate does.

How do I map a one-to-many relationship through a join table?

How would I go about mapping the following in NHibernate?
My entities and ERD are below. I know how to map a many-many relationship, but dont know how to map the joining table ReportTargets to the Datapoint table. You will notice that there is no ReportTargets entity model as it is not strictly a domain entity. What is the best solution here? I am a NHibernate newbie so go easy please..:) Thanks
http://img341.imageshack.us/img341/3769/entities.gif
As MarketReport.Targets has a join table, map it as many-to-many.
<class name="MarketReport">
<id column="reportid" />
<bag name="ReportTargets" table="reporttargets">
<key column="marketreportid"/>
<many-to-many column="targetid" class="Target"/>
</bag>
</class>
<class name="Target">
<id column="targetid" />
<bag name="DataPoints" inverse="true">
<key column="targetid"/>
<one-to-many class="DataPoint"/>
</bag>
</class>
<class name="DataPoint">
<id column="datapointid" />
</class>
Based on your most recent comment, you want either want a ternary association, or a component collection. I have included both mappings.
<class name="MarketReport">
<id column="reportid" />
<map name="ReportTargets" table="reporttargets">
<key column="marketreportid"/>
<index-many-to-many column="targetid" class="Target"/>
<many-to-many column="datapointid" class="DataPoint"/>
</map>
</class>
<class name="MarketReport">
<id column="reportid" />
<bag name="ReportTargets" table="reporttargets">
<key column="marketreportid"/>
<composite-element class="ReportTarget">
<many-to-one name="Target" column="targetid"/>
<many-to-one name="DataPoint" column="datapointid"/>
</composite-element>
</bag>
</class>
<class name="Target">
<id column="targetid" />
</class>
<class name="DataPoint">
<id column="datapointid" />
</class>

NHibernate: Make sure that the foreign key is not null

Is there anyway to make sure that when I export schema in NHibernate, I can make sure some of the columns must not be null?
For example, in the below case, the column Doc_ID in ReuploadTable must not be null:
<class name="Test.Generated.BusinessObjects.DocumentStore, DAL" table="document_store" lazy="true">
<id name="Id" column="Id">
<generator class="native" />
</id>
<bag name="ReuploadTables" lazy="true" cascade="all-delete-orphan" inverse="true" >
<key column="Doc_ID"></key>
<one-to-many class="ReuploadTable"></one-to-many>
</bag>
</class>
<class name="Test.Generated.BusinessObjects.ReuploadTable, DAL" table="reupload_table" lazy="true">
<id name="Id" column="ID">
<generator class="native" />
</id>
<property name="ReuploadTimes" column="ReuploadTimes" />
<property name="FilePath" column="FilePath" />
<many-to-one name="DocumentStore" column="Doc_ID" class="DocumentStore" />
</class>
And this is how I do the insertion:
Probably you can try to set
<key column="Doc_ID" not-null="true"></key>

NHibernate: Mapping multiple classes to the same view

I need to map two different classes to the same view and receive an error that a duplicate mapping exists. Is this possible in NHibernate? If not, can anyone give direction as to how I can solve this mapping problem.
I work with views which are set in stone. One view brings back data needed to split into two classes. The view looks like:
vw_player_points
----------------
Id
GameID
PlayerID
Points
The classes need to be 'player', with a list of games played
select gameid from vw_player_points where playerid = <PlayerID>
And each 'game' needs a list of players and their points:
select playerid, points from vw_player_points where gameid = <GameID>
I've tried table-per-concrete class inheritance aswell as mapping to the same view twice, but have had no joy :(
Here's the 'rough' mappings put into one xml snippet. Notice I also need to map to an interface (which works)
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="Test">
<class name="IPlayer" abstract="true">
<id name="Id" column="id">
<generator class="assigned"/>
</id>
<union-subclass name="Player" table="vw_player">
<bag name="Games">
<key column="player_id"/>
<one-to-many class="Test.IGame" not-found="ignore"/>
</bag>
</union-subclass>
</class>
<class name="IGame" abstract="true">
<id name="Id" column="game_id">
<generator class="assigned"/>
</id>
<union-subclass name="Game" table="vw_player_points">
<bag name="Points">
<key column="game_id"/>
<one-to-many class="Test.IPlayerPoints" not-found="ignore"/>
</bag>
</union-subclass>
</class>
<class name="IPlayerPoints" abstract="true">
<id name="Id" column="id">
<generator class="assigned"/>
</id>
<union-subclass name="PlayerPoints" table="vw_player_points">
<property not-null="false" name="PlayerId" column="player_id"/>
<property not-null="false" name="Points" column="points"/>
</union-subclass>
</class>
</hibernate-mapping>
It seems impossible to map multiple classes to a single view when using abstract/sub-class mapping of the form:
<class name="I[Entity]" abstract="true">
<union-subclass name="[Entity]">
...
</union-subclass>
</class>
I ended up mapping directly to the concrete classes using the proprty-ref attribute which works correctly:
<class name="Game" table="vw_player_points">
<id name="Id" column="id">
<generator class="hilo"/>
</id>
<property not-null="false" name="GameId" column="gameid"/>
<bag name="Points">
<key column="gameid" property-ref="GameId"/>
<one-to-many class="PlayerPoints" not-found="ignore"/>
</bag>
</class>
<class name="PlayerPoints" table="vw_player_points">
<id name="Id" column="id">
<generator class="hilo"/>
</id>
<property not-null="false" name="PlayerId" column="playerid"/>
<property not-null="false" name="Points" column="points"/>
</class>
Perhaps an 'abstract' sub-mapping type would negate the use of the union-subclass hack mapping to interfaces.