nhibernate : mapping to column other than primary key - nhibernate

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.

Related

Yet another one on "deleted object would be re-saved by cascade (remove deleted object from associations)"

Most all of the references to this NHibernate error (in the title) talk about child objects being deleted while still contained in a parent collection that would only re-save them later negating their "delete" (which is what the error states and the suggestion to remove object from associations that are re-saving it).
But in my case, the error happens while deleting the parent record (then the "child" is deleted via the association, so I don't want the association removed, as the error suggest)
It would have made sense if that happened every time, but I only observe this error intermittently, running exactly the same code but only against particular records. Other identical records don't trigger the condition and the delete goes through (all the time I deal with one Customer with two address-es.)
Not sure how much and what code to show. This is my "parent" object mapping:
I've got a OneCustomer-to-ManyAddresses relation mapped as a "set" of CustomerAddress "composite elements"
<class name="Customer" table="Customer">
<id name="Id" column="[Id]" type="Guid">
<generator class="guid" />
</id>
...
<set name="AddressList" lazy="true" table="CustomerAddress" cascade="all-delete-orphan" >
<key column="[CustomerId]"/>
<composite-element class="CustomerAddress">
<parent name="Customer"/>
<many-to-one name="Address"
class="Address"
column="[AddressId]"
not-null="true"
cascade="all"/>
...
</composite-element>
</set>
And this is the mapping for the "composite" object CustomerAddress:
<class name="CustomerAddress" table="CustomerAddress" >
<id name="Id" column="[Id]" type="Guid">
<generator class="guid" />
</id>
<many-to-one
name="Address"
column="[AddressId]"
class="Address"
not-null="true"
cascade="all"/>
<many-to-one
name="Customer"
column="[CustomerId]"
class="Customer"
not-null="true"
cascade="all"/>
...
</class>
What is the explanation of the error and its intermittent nature?
ADDITIONAL INFO
After further examination - looking for another collection that may hold a reference to same "Address" child, I saw the following mapping:
<class name="Address" table="Address">
<id name="Id" column="[id]" type="Guid" >
<generator class="guid" />
</id>
<!-- REMOVING THE FOLLOWING <BAG> SEEMS TO BE FIXING MY ISSUE -->
<bag name="CustomerAddressList" inverse="true" cascade="none" lazy="false" >
<key>
<column name="[AddressId]" />
</key>
<one-to-many class="CustomerAddress" />
</bag>
</class>
Removing the <bag name="CustomerAddressList"... seems to fix my issue. Explanation?
I'm going to have a guess:
You have a bi-directional association, but you haven't specified that one of them is the non-owner (by setting "inverse = true").
Try modifying the CustomerAddress relationship as follows:
<class name="CustomerAddress" table="CustomerAddress" >
<id name="Id" column="[Id]" type="Guid">
<generator class="guid" />
</id>
<many-to-one
name="Address"
column="[AddressId]"
class="Address"
not-null="true"
cascade="all"/>
<many-to-one
name="Customer"
column="[CustomerId]"
class="Customer"
not-null="true"
cascade="all"
inverse="true"
/>
...
</class>
why do you have two mappings for CustomerAddress table (one as composite Element and one as Entity)? remove the entity mapping for Customer address and it should work.

How to create NHibernate relationship mapping between multiple entities to another entity (i.e inheritance mapping)

I have this relationship between Car, Bike, Skateboard object with a Person object.
The relationship is stored in Ownership table.
How do I create this mapping in NHibernate ? I'm trying to follow this tutorial: http://nhibernate.info/doc/nh/en/index.html#inheritance. Any help is appreciated.
Here is the way I might do it.
<class lazy="false" name="Domain.OwnerShip, Domain" table="OwnerShip_Table">
<id name="Id" column="OwnerShipId" type="System.Int32" access="property">
<generator class="identity"></generator>
</id>
<joined-subclass name="Car" table="Cars" lazy="false">
<key column="Id" />
<property name="Owner" />
</joined-subclass>
<joined-subclass name="Bike" table="Bikes" lazy="false">
<key column="Id" />
<property name="Owner" />
</joined-subclass>
<joined-subclass name="Skateboard" table="Skateboards" lazy="false">
<key column="Id" />
<property name="Owner" />
</joined-subclass>
</class>
You would probably want a Persons table as well as a Person Entity with a mapping where Person has a Bag of OwnedVehicles.
Here is an option, with a table per hierarchy.
I assume :
Ownership holds its own Id (OwnerShipId, auto-generated)
you have a column per referenced class/table (BikeId, CarId), to handle different key types and foreign keys
The mapping would then look something like :
<class lazy="false" name="Domain.OwnerShip, Domain" table="OwnerShip_Table" discriminator-value="0">
<id name="Id" column="OwnerShipId" type="System.Int32" access="property">
<generator class="identity"></generator>
</id>
<discriminator column="VehicleTypeCode" type="int"/>
<many-to-one name="Owner" column="PersonId" not-null="true" fetch="..."/>
<many-to-one name="CodeType" column="VehicleTypeCode" not-null="true" fetch="..." />
<subclass name="Domain.BikeOwnerShip, Domain" discriminator-value="1">
<many-to-one name="Bike" column="BikeId" not-null="true" fetch="..."/>
</subclass>
<subclass name="Domain.CarOwnerShip, Domain" discriminator-value="2">
<many-to-one name="Car" column="CarId" not-null="true" fetch="..."/>
</subclass>
</class>
I guess it would also be nice to have a virtual, not mapped, OwnedObject property in the base class, something like
public virtual Object OwnedObject{
get{return null;}
}
in the CarOwnership class the OwnedObject implementation would be
public override Object OwnedObject{
get{return this.Car;}
}
Hope this will help

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.

nhibernate newbe question ... easy one here

I'm new to nhibernate so this should be easy. I have a mapping file as below although I deleted some fields that aren't relevant to this question. The streamfields class contains a bag of fieldmappings. I want the join to be on field_no column but the sql that is sent is on the id field (str_fld_id") as seen below.
I see what the below sql is doing but it's not what I wanted. It's trying to query the field_mappings table based on the values found in the id column str_fld_id in the StreamFields class when I thought it was clear I wanted the field_no to be used on both ends. I say I thought it was clear because the mapping for the field_mapping class has the below attribute and they both have the same named field
Below is in my FieldMappings mapping file.
<many-to-one name="FieldNo" cascade="none" column="`Field_No`" not-null="true">
Sql sent
NHibernate: SELECT fkfieldmap0_.[field_no] as field5_1_, fkfieldmap0_.[Mapping_Id] as Mapping1_1_, fkfieldmap0_.[Mapping_Id] as Mapping1_3_0_, fkfieldmap0_.[Std_fld_Id] as Std2_3_0_, fkfieldmap0_.[Field_Position] as Field3_3_0_, fkfieldmap0_.[Field_No] as Field4_3_0_ FROM [Field_Mappings] fkfieldmap0_ WHERE fkfieldmap0_.[field_no]=#p0; #p0 = '20'
StreamFields mapping
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DataTransfer.StreamFields,DataTransfer" table="`stream_fields`" lazy="true">
<id name="StrFldId" column="`str_fld_id`" type="int">
<generator class="native" />
</id>
<property type="int" not-null="true" name="FieldNo" column="`field_no`" />
<many-to-one name="StreamId" cascade="none" column="`stream_Id`" />
<bag name="FkFieldMappingsStreamFields" inverse="true" lazy="false" cascade="all">
<key column="`field_no`" />
<one-to-many class="DataTransfer.FieldMappings,DataTransfer"/>
</bag>
</class>
[Edited - with old comments]
Okay, i think i finally got you right and i might admit the problems i had understanding what you want took me a while and result of the lack of information you provided. In the future please provide the mapping of both tables clarify on the point wheather it is a mapping or a query issue. Thx.
IMO you have misunderstood the idea of a parent/child-relation.
The bag you mentioned like to have within the StreamFields class shouldn't be a bag but a direct association. Like this:
<class name="DataTransfer.StreamFields,DataTransfer" table="stream_fields" >
<id name="StrFldId" column="str_fld_id" type="int">
<generator class="native" />
</id>
<property type="int" not-null="true" name="FieldNo" column="field_no" />
<many-to-one name="FieldMapping" class="FiueldMapping" column="Field_No" />
</class>
This of course will only work if you have a property of type FiledMapping in your class.
You want to map FieldMapping to the column Field_No within StreamFields class. There can only be one value within this column, so a bag makes no sense at all. If you want to have a bag of course you can keep it the way it already worked but be aware that the 'key-column' within the bag refers to the child table - in an other way it makes no sense cause a ForeignKey has to map to a PrimaryKey on its parent table. This ensures it is unique and set.
I really don't want to rant but would strongly encourage you to review the hibernate reference about collection mapping to get a deeper clue however.
Hopely this will solve your problem.
Below are the mappings for the classes.
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DataTransfer.StreamFields,DataTransfer" table="`stream_fields`" lazy="true">
<id name="StrFldId" column="`str_fld_id`" type="int">
<generator class="native" />
</id>
<property type="string" length="50" name="FieldName" column="`field_name`" />
<property type="int" name="InputFieldPosition" column="`input_field_position`" />
<property type="int" name="Start" column="`start`" />
<property type="int" name="Width" column="`width`" />
<property type="string" length="50" name="Datatype" column="`datatype`" />
<property type="int" not-null="true" name="FieldNo" column="`field_no`" />
<property type="int" name="FieldOrder" column="`field_order`" />
<property type="int" name="StdId" column="`Std_Id`" />
<many-to-one name="StreamId" cascade="none" column="`stream_Id`" />
<bag name="FkFieldMappingsStreamFields" inverse="true" lazy="false" cascade="all">
<key column="`field_no`" />
<one-to-many class="DataTransfer.FieldMappings,DataTransfer"/>
</bag>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DataTransfer.FieldMappings,DataTransfer" table="`Field_Mappings`" lazy="false">
<id name="MappingId" column="`Mapping_Id`" type="int">
<generator class="native" />
</id>
<property type="int" name="StdFldId" column="`Std_fld_Id`" />
<property type="int" name="FieldPosition" column="`Field_Position`" />
<many-to-one name="FieldNo" cascade="none" column="`Field_No`" not-null="true" property-ref="FieldNo" />
</class>
</hibernate-mapping>
To make things easy on myself, there is one record in stream_fields and the field_no value is 1 and 20 is the value in StrFldId.
SELECT fkfieldmap0_.[field_no] as field5_1_, fkfieldmap0_.[Mapping_Id] as Mapping1_1_, fkfieldmap0_.[Mapping_Id] as Mapping1_3_0_, fkfieldmap0_.[Std_fld_Id] as Std2_3_0_, fkfieldmap0_.[Field_Position] as Field3_3_0_, fkfieldmap0_.[Field_No] as Field4_3_0_ FROM [Field_Mappings] fkfieldmap0_ WHERE fkfieldmap0_.[field_no]=#p0; #p0 = '20' –