I'm trying to save an object that contains a bag with a many to many relationship.
The problem is that the object is saved correctly but the bag isn't.
Here is my mapping, can anyone tell me what I'm doing wrong.
Thanks
<class name="XManager.Business.Afspraak, XManager.Business" table="Afspraak" lazy="false" mutable="false">
<id name="Id" type="int">
<generator class="identity" />
</id>
<property name="StartDatum" column="StartDatum"/>
<property name="EindDatum" column="EindDatum"/>
<property name="Herhalend" column="Herhalend"/>
<property name="HerhaalInterval" column="HerhaalInterval"/>
<property name="Opmerking" column="Opmerking"/>
<property name="Status" column="Status"/>
<property name="ToevoegDatumTijd" column="ToevoegDatumTijd"/>
<property name="WijzigDatumTijd" column="WijzigDatumTijd"/>
<many-to-one name="Klant" column="KlantId" class="Klant"/>
<bag name="Behandelingen" table="AfspraakBehandelingen" lazy="false" cascade="all-delete-orphan">
<key column="AfspraakId"/>
<many-to-many class="Behandeling" column="BehandelingId"/>
</bag>
<class name="XManager.Business.Behandeling, XManager.Business" table="Behandeling" lazy="false" mutable="false">
<id name="Id" type="int">
<generator class="identity" />
</id>
<property name="Naam" column="Naam"/>
<property name="Omschrijving" column="Omschrijving"/>
<property name="Duur" column="Duur"/>
<property name="Prijs" column="Prijs"/>
<property name="ToevoegDatumTijd" column="ToevoegDatumTijd"/>
<property name="WijzigDatumTijd" column="WijzigDatumTijd"/>
<many-to-one name="Categorie" column="CategorieId" class="Categorie"/>
Try inverse=true in the bag definition
Related
I'm trying to save my order object in the database that has a relationship many-to-one with the table pastaIndividual.
But, I'm getting this exception:
Error: NHibernate.Exceptions.GenericADOException: could not insert:
[FrancosPoS.DBMapping.order][SQL: INSERT INTO order (price, cash,
credit, obs) VALUES (?, ?, ?, ?);SELECT LAST_INSERT_ID()] --->
MySql.Data.MySqlClient.MySqlException: You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'order (price, cash, credit, obs)
VALUES ('123', 1, 0, 'Nhibernate');SELECT LAST_' at line 1
Here is my order mapping table:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="FrancosPoS" namespace="FrancosPoS.DBMapping" xmlns="urn:nhibernate-mapping-2.2">
<class name="order" table="order" lazy="true" >
<id name="idOrder">
<generator class="identity" />
</id>
<set name="pastaIndividual" table="pasta_individual" cascade="save-update">
<key column="idPastaI"/>
<one-to-many class="pastaIndividual"/>
</set>
<!--<many-to-one insert="false" update="false" lazy="false" name="pastaIndividual" class="FrancosPoS.DBMapping.pastaIndividual">
<column name="idPastaI" sql-type="int(11)" not-null="false" />
</many-to-one>-->
<many-to-one insert="false" update="false" lazy="false" name="pastaCombo" class="FrancosPoS.DBMapping.pastaCombo">
<column name="idPastaC" sql-type="int(11)" not-null="false" />
</many-to-one>
<many-to-one insert="false" update="false" lazy="false" name="pastaFeast" class="FrancosPoS.DBMapping.pastaFeast">
<column name="idPastaF" sql-type="int(11)" not-null="false" />
</many-to-one>
<many-to-one insert="false" update="false" lazy="false" name="salad" class="FrancosPoS.DBMapping.salad">
<column name="idSalad" sql-type="int(11)" not-null="false" />
</many-to-one>
<many-to-one insert="false" update="false" lazy="false" name="drink" class="FrancosPoS.DBMapping.drink">
<column name="idDrink" sql-type="int(11)" not-null="false" />
</many-to-one>
<property name="price">
<column name="price" sql-type="decimal(8,4)" not-null="true" />
</property>
<property name="cash">
<column name="cash" sql-type="tinyint(1)" not-null="false" />
</property>
<property name="credit">
<column name="credit" sql-type="tinyint(1)" not-null="false" />
</property>
<property name="obs">
<column name="obs" sql-type="varchar(150)" not-null="false" />
</property>
</class>
</hibernate-mapping>
Here is my pastaIndividual mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="FrancosPoS" namespace="FrancosPoS.DBMapping" xmlns="urn:nhibernate-mapping-2.2">
<class name="pastaIndividual" table="pasta_individual" lazy="true" >
<id name="idPastaI">
<generator class="identity" />
</id>
<property name="type">
<column name="type" sql-type="varchar(25)" not-null="true" />
</property>
<property name="price">
<column name="price" sql-type="decimal(8,4)" not-null="true" />
</property>
</class>
</hibernate-mapping>
I've tried on order mapping to use the <set> or just <many-to-one>, but the same error happen.
Maybe am I missing some inverse property?
Thanks.
Order is a reserved word. just add some back ticks to your class definition and NHibernate will escape the table name for you automatically.
<class name="order" table="`order`" lazy="true" >
What's wrong with this mapping?
On saving an instance of Class3, two rows in Table_2 will be inserted!
first row has Column4 set to null and correct value of Column3,
and second row has Column3 set to null and correct value of Column4!
<class name="Class1" table="Table_1">
<id name="Column1">
<generator class="native" />
</id>
<discriminator column="ColumnDisc" />
<property name="Column2" type="int" />
<subclass name="Class2">
<join table="Table_2">
<key column="Column1" />
<property name="Column3" type="int" />
</join>
<subclass name="Class3" >
<join table="Table_2">
<key column="Column1" />
<property name="Column4" type="int" />
</join>
</subclass>
</subclass>
</class>
Where do you set the discriminator value for each of the derived types?
If I believe the link to which you pointed in your comment, the class mapping looks like this:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.javalobby.tnt.hib.User" table="USER" lazy="false">
<id name="id" type="long" column="ID">
<generator class="identity" />
</id>
<discriminator column="type" type="string"/>
<property name="firstName" column="first_name"/>
<property name="lastName" column="last_name"/>
<subclass name="com.javalobby.tnt.hib.Employee" discriminator-value="employee">
<join table="employee">
<key column="id"/>
<property name="jobTitle" column="job_title"/>
<many-to-one name="supervisor" column="supervisor_id" not-null="true" />
</join>
<subclass name="com.javalobby.tnt.hib.Employer" discriminator-value="employer">
<set name="subordinates">
<key column="supervisor_id" not-null="true"/>
<one-to-many class="com.javalobby.tnt.hib.Employee"/>
</set>
<join table="employer">
<key column="id"/>
<property name="companyCarBrand" column="company_car_brand"/>
</join>
</subclass>
</subclass>
</class>
If I compare your mapping with this one, you lack discriminator-value attribute within your <subclass> tag.
<class name="Class1" table="Table_1">
<id name="Column1">
<generator class="native" />
</id>
<discriminator column="ColumnDisc" />
<property name="Column2" type="int" />
<subclass name="Class2"> <!-- The discriminator-value="" is missing here... -->
<join table="Table_2">
<key column="Column1" />
<property name="Column3" type="int" />
</join>
<subclass name="Class3" > <!-- The discriminator-value="" is missing here... -->
<join table="Table_2">
<key column="Column1" />
<property name="Column4" type="int" />
</join>
</subclass>
</subclass>
</class>
Make sure you set the right discriminator values for each of the subclasses you intend to map. I suggest trying this and figure out whether it works better, or if this raised another problem. =)
Hope this helps! =)
I have a mapping file
<set name="Friends" table="Friends">
<key column="UserId"/>
<many-to-many class="User" column="FriendId"/>
</set>
I would like to specify extra columns for the friend table this creates.
For example Approve (the user must approve the friend request)
Is there a easy way?
And update
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping namespace="MyVerse.Domain" assembly="MyVerse.Domain" xmlns="urn:nhibernate-mapping-2.2">
<class name="User" table="[User]" lazy="true">
<id name="Id" type="Guid">
<generator class="guid" />
</id>
<property name="DateCreated" type="DateTime" not-null="true" />
<property name="Deleted" type="Boolean" not-null="true" />
<property name="Firstname" type="String" length="100" not-null="true" />
<property name="Lastname" type="String" length="100" not-null="true" />
<bag name="Friends" table="[Friend]">
<key column="UserId"/>
<many-to-many class="Friend" column="FriendId"/>
</bag>
</class>
<class name="Friend" table="[Friend]" lazy="true">
<id name="Id" type="Guid">
<generator class="guid" />
</id>
<property name="DateCreated" type="DateTime" not-null="true" />
<property name="Approved" type="Boolean" not-null="true" />
</class>
</hibernate-mapping>
Will cause a link to the friend table from the friend table
If a set has "extra properties", you must convert it into a proper entity.
So, a User doesn't have an ISet<User>; it has an ISet<Friend>.
When I save a new Report, NHibernate inserts the Report, ignores the Publication and tries to insert the UserPublication. However SQL then complains about violation of FK constraint.
Its like NHibernate doesn't think the Publication is new even though the row doesn't exist in the db.
Think of the entity relationship as:
A Report can have many Publications (Publications belong to a Report)
A Publication can have many UserPublications (UserPublications belong to a Publication)
Any ideas what I've done wrong?
Thanks in advance.
Here's the mappings:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="Model.Report, Model" table="Report" lazy="true">
<id name="Id" access="property" column="ReportID">
<generator class="assigned"></generator>
</id>
<property name="DeleteUnread" access="property" />
<property name="Description" access="property" />
<property name="Name" access="property" />
<bag name="Publications" access="property" lazy="true" cascade="all-delete-orphan">
<key column="ReportID"/>
<one-to-many class="Model.Publication, Model"/>
</bag>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="Model.Publication, Model" table="Publication" lazy="true">
<id name="Id" access="property" column="PublicationID">
<generator class="assigned"></generator>
</id>
<property name="CreatedOn" access="property" />
<property name="FileExtension" access="property" />
<property name="IsDownloaded" access="property" />
<property name="ToBeDownloaded" access="property" />
<property name="Name" access="property"/>
<bag name="UserPublications" access="property" lazy="true" cascade="all-delete-orphan">
<key column="PublicationID"></key>
<one-to-many class="Model.UserPublication, Model" />
</bag>
<many-to-one name="Report" class="Model.Report, Model" lazy="false" column="ReportID" not-null="true" cascade="none">
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="Model.UserPublication, Model" table="UserPublication" lazy="true">
<id name="Id" access="property" column="UserPublicationID">
<generator class="native"></generator>
</id>
<property name="IsFlaggedForDeletion" access="property" column="IsFlaggedForDeletion" />
<property name="HasBeenRead" access="property" column="HasBeenRead" />
<property name="DateReceived" access="property" column="DateReceived" />
<property name="MustRead" access="property" column="MustRead" />
<property name="ShowToolbar" access="property" column="ShowToolbar" />
<property name="MaxAge" access="property" column="MaxAge" />
<property name="FeedId" access="property" column="FeedId" />
<property name="CanEdit" access="property" column="CanEdit" />
<many-to-one name="User" access="property" column="ClientUserID" class="Model.ClientUser, Model" not-null="true" cascade="none">
</many-to-one>
<many-to-one name="Publication" access="property" class="Model.Publication, Model" column="PublicationID" not-null="true" cascade="none">
</many-to-one>
</class>
I think the problem is that id of publications is an assigned id therefore NHibernate can't recognize when it should insert a publication.
When you flush a session it first insert all inserted objects , then it updates all updated objects and then deletes all deleted objects.
So I think that's going to happen here:
You save a Report that has publications that have userpublications.Since publication id is assigned NHibernate assumes it has to be updated and ignore it but UserPublication id is native and NHibernates knows when it should be inserted and tries to insert it thus a FK violation happens.
To solve this problem you can add a version property to publication so NHibernate can insert it based on its version value.
The UserPublications bag in the Publication class has a wrong key element. It should be:
<key column="PublicationID"/>
This works. I set the unsaved-value attribute to "any".
I don't think there will be any repurcussions.
<id name="Id" access="property" column="PublicationID" unsaved-value="any">
<generator class="assigned"></generator>
</id>
I don't understand why NHibernate is trying to insert the parent object - when the row already exists in the db - when I'm inserting the child row.
Parent mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="ReportDistribution.Client.ReportMgr.Model.ClientReport, ReportDistribution.Client.ReportMgr.Model"
table="ClientReport"
lazy="false"
dynamic-update="true">
<id name="Id" access="property" column="ReportID">
<generator class="assigned"></generator>
</id>
<property name="MaxAge" access="property" />
<property name="DeleteUnread" access="property" />
<property name="Description" access="property" />
<property name="Name" access="property" />
<bag name="ClientPublications" cascade="all" lazy="false">
<key column="ReportID" />
<one-to-many class="ReportDistribution.Client.ReportMgr.Model.ClientPublication, ReportDistribution.Client.ReportMgr.Model" />
</bag>
</class>
</hibernate-mapping>
Child mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="ReportDistribution.Client.ReportMgr.Model.ClientPublication, ReportDistribution.Client.ReportMgr.Model"
table="ClientPublication"
lazy="false"
dynamic-update="true">
<id name="Id" access="property" column="PublicationID">
<generator class="assigned"></generator>
</id>
<property name="CreatedOn" access="property" type="DateTime"></property>
<property name="IsMarkedForDeletion" access="property"></property>
<property name="IsDeleted" access="property"></property>
<property name="HasBeenRead" access="property"></property>
<property name="ReceivedOn" access="property" type="DateTime"></property>
<property name="FileExtension" access="property"></property>
<property name="IsDownloaded" access="property"></property>
<property name="MustRead" access="property"></property>
<many-to-one
name="Report"
class="ReportDistribution.Client.ReportMgr.Model.ClientReport, ReportDistribution.Client.ReportMgr.Model"
lazy="false"
column="ReportID">
</many-to-one>
</class>
</hibernate-mapping>
The Parent class (Report) has property which is a collection of child classes.
The Child class (Publication) has property which is the parent object.
Thanks in advance....
It sounds to me like the parent object is no longer connected to the session when you are saving the child. HNibernate tracks the state of entities that are connected to a session, but if the entity becomes detached it loses the ability to track state.
Think of it like this - if an entity has not come through the exact instance of ISession you are currently using, then it doesn't know it exists. Hence, it treats everything it's never seen as if it were "new."
One option could be to use the ISession.Load(entity); to reload your parent prior to saving.