Unidirectional many-to-many insert using dynamic session in NHibernate - nhibernate

I've the "AnagraficaBase" hbm file:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class entity-name="AnagraficaBase" table="anagrafica">
<id name="ID" type="int" >
<column name="ID" not-null="true" />
<generator class="identity" />
</id>
<property name="Email" type="string" >
<column name="Email" sql-type="varchar(255)" not-null="true" />
</property>
<one-to-one cascade="all" class="NetCms.Users.User" property-ref="AnagraficaMapped" name="User" />
<joined-subclass entity-name="Anagraficaprova" table="anagrafica_prova" >
<key>
<column name="id_anagrafica_prova" />
</key>
<property name="data di nascita" type="DateTime">
<column name="data_di_nascita" sql-type="DateTime" not-null="true" />
</property>
<property name="nome" type="string">
<column name="nome" sql-type="varchar(25)" not-null="true" />
</property>
<property name="dropdown test" type="string">
<column name="dropdown_test" sql-type="varchar(255)" not-null="true" />
</property>
<bag name="profilo" table="anagrafica_prova_custom_field_checkboxlist_values" cascade="all" fetch="select">
<key>
<column name="IDanagrafica_prova" not-null="true" />
</key>
<many-to-many entity-name="CustomCheckboxListValue">
<column name="IDcustom_field_checkboxlist_value" not-null="true" />
</many-to-many>
</bag>
</joined-subclass>
</class>
</hibernate-mapping>
I want to create an "Anagraficaprova" object with dynamic session (EntityMode.Map).
As you can see, I've a unidirectional many to many relation between "Anagraficaprova" and "CustomCheckboxListValue".
So, when I do:
ISession mapSession = sess.GetSession(EntityMode.Map);
List<IDictionary> profiles = new List<IDictionary>();
Hashtable profilo1 = (Hashtable) mapSession.get("CustomCheckboxListValue",1);
profiles.add(profilo1);
Hashtable anagraficaProva = new Hashtable();
anagraficaProva.add("Email","test");
anagraficaProva.add("data di nascita", "08/10/1982");
anagraficaProva.add("nome","pippo");
anagraficaProva.add("dropdown test","1");
anagraficaProva.add("profilo", profiles);
mapSession.SaveOrUpdate("Anagraficaprova", anagraficaProva);
The anagraficaProva object is correctly saved, but the record in "anagrafica_prova_custom_field_checkboxlist_values" table (the couple: IDanagrafica_prova,IDcustom_field_checkboxlist_value) is not inserted.
Where is the problem?
Thank you...

In case someone else comes here.
NH inserts AnagraficaBase because it uses identity to get the id but batches the Inserts into table anagrafica_prova_custom_field_checkboxlist_values to insert them in one go later. But before they are sent to db the session is thrown away and therefor the batched Inserts.
mapSession.Flush(); after SaveOrUpdate tells NH to send all pending statements.

Related

GenericADOException: could not insert

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" >

Saving manually created objects using NHibernate

I am trying to use NHibernate to save an object that was completely manually created. My mappings are in place and I currently have no data in the database. Everytime I call Save() or SaveOrUpdate(), NHibernate does a select statement for what I am trying to save. Then it gives me the exception: "a different object with the same identifier value was already associated with the session". Does anyone know how I can tell NHibernate to save my manually instantiated object without thinking that a different object has already been loaded?
Additional Information:
I have a primary mapping with a one-to-many collection. The exception is telling me that "a different object with the same identifier has been loaded", on the collection, not the parent object. I don't know if this provides any useful information. The mappings are as follows:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Program.Application.Models" assembly="Company.Application.Models">
<class name="ProductVersion" table="ClientVersion" lazy="false">
<composite-id>
<key-property name="PracticeName">
<column name="practiceName" not-null="true" />
</key-property>
<key-property name="Address">
<column name="address" not-null="true" />
</key-property>
<key-property name="City">
<column name="city" not-null="true" />
</key-property>
<key-property name="State">
<column name="state" not-null="true" />
</key-property>
<key-property name="Zip">
<column name="zip" not-null="true" />
</key-property>
</composite-id>
<property name="LegalName" column="legalName" />
<property name="Version" column="version" />
<bag name="ProductsLicensesDetail" inverse="true" lazy="false" >
<key>
<column name="practiceName" />
<column name="address" />
<column name="city" />
<column name="state" />
<column name="zip" />
</key>
<one-to-many class="ProductLicenseDetail" />
</bag>
</class>
</hibernate-mapping>
and
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Program.Application.Models" assembly="Program.Application.Models">
<class name="ProductLicenseDetail" table="ClientProductLicense">
<id name="ProductCode" column="productCode">
<generator class="assigned" />
</id>
<property name="TotalEnterpriseLicenses" column="totalEnterpriseLicenses" />
<property name="EnterpriseLicensesUsed" column="enterpriseLicensesUsed" />
<property name="TotalPracticeLicenses" column="totalPracticeLicenses" />
<property name="PracticeLicensesUsed" column="practiceLicensesUsed" />
<property name="TotalProviderLicenses" column="totalProviderLicenses" />
<property name="ProviderLicensesUsed" column="providerLicensesUsed" />
<property name="TotalUserLicenses" column="totalUserLicenses" />
<property name="UserLicensesUsed" column="userLicensesUsed" />
<property name="LicenseKey" column="licenseKey" />
<property name="LicenseActivationDate" column="licenseActivationDate" />
<property name="LicenseExpirationDate" column="licenseExpirationDate" />
<many-to-one name="ProductVersion" class="ProductVersion" cascade="none">
<column name="practiceName" />
<column name="address" />
<column name="city" />
<column name="state" />
<column name="zip" />
</many-to-one>
</class>
</hibernate-mapping>
NHibernate is telling me that "a different object with the same identifier value was already associated with the session" for the ProductCode key of the second mapping. Any insight would greatly be appreciated. Thank you.
I believe you will need to add a version field to your composite key class and mapping; see this article for further details.
Have you tried
session.SaveOrUpdateCopy(entity);
session.Flush();
?

Nhibernate <version> feature not working

I have just started working with NHibernate. Have found it pretty good till now but have hit an issue that I am unable to solve. Any help will be greatly appreciated.
I am trying to use the "version" feature to help implement optmistic locking. Below is my mapping file and a portion of code from the related class. My problem is that no matter how many times I modify any field, the "Version" column on the database does not get updated.
My mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="MyTest"
assembly ="MyTest">
<class name="Project" table="dbo.M_Project">
<id name="ProjectId" type="Int32" unsaved-value="null">
<column name="ProjectId" sql-type="int" not-null="true" unique="true" />
<generator class="native" />
</id>
<version name="Version" column="Version"/>
<property name="ProjectName" type="String">
<column name="ProjectName" length="100" sql-type="nvarchar" not-null="true"/>
</property>
<property name="Updated" type="bool">
<column name="Updated" sql-type="bit" not-null="true"/>
</property>
<property name="NoOfItemsWithExceptions" type="int">
<column name="NoOfItemsWithExc" sql-type="int" not-null="true"/>
</property>
<property name="MenuState" type="int">
<column name="MenuState" sql-type="int" not-null="true"/>
</property>
<property name="Initialized" type="bool">
<column name="Initialized" sql-type="bit" not-null="true"/>
</property>
<property name="InventoryRun" type="bool">
<column name="InventoryRun" sql-type="bit" not-null="true"/>
</property>
<property name="ProductionForecastRun" type="bool">
<column name="ProductionForecastRun" sql-type="bit" not-null="true"/>
</property>
<property name="MonthlyUpdate" type="bool">
<column name="MonthlyUpdate" sql-type="bit" not-null="true"/>
</property>
<bag name="SKUList" table="dbo.P_SKU" inverse="true" lazy="true" cascade="save-update">
<key column="ProjectId" />
<one-to-many
class="SKU"/>
</bag>
</class>
</hibernate-mapping>
The associated version property:
private int _version;
public virtual int Version
{
get { return _version; }
set { _version = value; }
}
Thanks!
It might be necessay to explicity set the optimistic-lock attribute (in theory it's not). For instance
<class name="Project" table="dbo.M_Project" optimistic-lock="dirty">
Here you have more info about it

NHibernate Mapping + Iset

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>.

NHibernate not inserting parent into the db

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>