Nhibernate <version> feature not working - nhibernate

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

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

Unidirectional many-to-many insert using dynamic session in 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.

NHibernate, could not load an entity when column exists in the database

This is probably a simple question to answer but I just can't figure it out.
I have a "Company" class with a many-to-one to "Address" which has a many to one to a composite id in "City". When I load a "Company" it loads the "Address", but if I call any property of "Address" I get the error:
{"could not load an entity: [IDI.Domain.Entities.Address#2213][SQL: SELECT address0_.AddressId as AddressId13_0_, address0_.Street as Street13_0_, address0_.floor as floor13_0_, address0_.room as room13_0_, address0_.postalcode as postalcode13_0_, address0_.CountryCode as CountryC6_13_0_, address0_.CityName as CityName13_0_ FROM Address address0_ WHERE address0_.AddressId=?]"}
The inner exception is:
{"Invalid column name 'CountryCode'.\r\nInvalid column name 'CityName'."}
What I don't understand is that I can run the query in sql server 2005 and it works, furthermore both those columns exist in the address table.
Here are my HBMs:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="IDI.Domain" namespace="IDI.Domain.Entities" >
<class name="IDI.Domain.Entities.Company,IDI.Domain" table="Companies">
<id column="CompanyId" name="CompanyId" unsaved-value="0">
<generator class="native"></generator>
</id>
<property column="Name" name="Name" not-null="true" type="String"></property>
<property column="NameEng" name="NameEng" not-null="false" type="String"></property>
<property column="Description" name="Description" not-null="false" type="String"></property>
<property column="DescriptionEng" name="DescriptionEng" not-null="false" type="String"></property>
<many-to-one name="Address" column="AddressId" not-null="false" cascade="save-update" class="IDI.Domain.Entities.Address,IDI.Domain"></many-to-one>
<property column="Telephone" name="Telephone" not-null="false" type="String"></property>
<property column="TelephoneTwo" name="TelephoneTwo" not-null="false" type="String"></property>
<property column="Fax" name="Fax" not-null="false" type="String"></property>
<property column="ContactMan" name="ContactMan" not-null="false" type="String"></property>
<property column="ContactManEng" name="ContactManEng" not-null="false" type="String"></property>
<property column="Email" name="Email" not-null="false" type="String"></property>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="IDI.Domain" namespace="IDI.Domain.Entities" >
<class name="IDI.Domain.Entities.Address,IDI.Domain" table="Address">
<id name="AddressId" column="AddressId" type="Int32">
<generator class="native"></generator>
</id>
<property name="Street" column="Street" not-null="false" type="String"></property>
<property name="Floor" column="floor" not-null="false" type="Int32"></property>
<property name="Room" column="room" not-null="false" type="Int32"></property>
<property name="PostalCode" column="postalcode" not-null="false" type="string"></property>
<many-to-one class="IDI.Domain.Entities.City,IDI.Domain" name="City" update="false" insert="false">
<column name="CountryCode" sql-type="String" ></column>
<column name="CityName" sql-type="String"></column>
</many-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="IDI.Domain" namespace="IDI.Domain.Entities" >
<class name="IDI.Domain.Entities.City,IDI.Domain" table="Cities">
<composite-id>
<key-many-to-one class="IDI.Domain.Entities.Country,IDI.Domain" name="CountryCode" column="CountryCode">
</key-many-to-one>
<key-property name="Name" column="Name" type="string"></key-property>
</composite-id>
</class>
</hibernate-mapping>
Here is my code that calls the Company:
IList<BursaUser> user;
if(String.IsNullOrEmpty(email) && String.IsNullOrEmpty(company))
return null;
ICriteria criteria = Session.CreateCriteria(typeof (BursaUser), "user").CreateCriteria("Company", "comp");
if(String.IsNullOrEmpty(email) || String.IsNullOrEmpty(company) )
{
user = String.IsNullOrEmpty(email) ?
criteria.Add(Expression.Eq("comp.Name", company)).List<BursaUser>()
: criteria.Add(Expression.Eq("user.Email", email)).List<BursaUser>();
}
And finally here is where i get the error:
"user" was already initialized with the code above:
if (user.Company.Address.City == null)
user.Company.Address.City = new City();
Thanks.

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>

Nhibernate bag is not saved

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