nhibernate many-to-many bag not inserting in the association table - nhibernate

I know this has been asked and answered a number of times, but I have two classes that are many-to-many. I've reciprocal mapped them using bags. Here is the NHibernate Mapping:
Calendar:
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by NHibernate.Mapping.Attributes on 2009-10-09 18:09:29Z.-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Calendar.Calendar, Calendar" table="Calendars">
<id name="CalendarId" column="CalendarId" type="Int32">
<generator class="native" />
</id>
<property name="Name" length="100" />
<property name="CalendarStatus" />
<property name="CalendarType" type="Calendar.GenericEnumMapper`1[[Calendar.CalendarType, Calendar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Calendar" length="50" />
<property name="RecordCreatedBy" column="CreatedBy" length="50" />
<property name="RecordModifiedBy" column="ModifiedBy" length="50" />
<property name="CreateDate" />
<property name="ModifiedDate" />
<bag name="Events" table="CalendarEventsInCalendar" cascade="all">
<key column="CalendarId" />
<many-to-many class="Calendar.CalendarEvent, Calendar" column="CalendarEventId" />
</bag>
</class>
</hibernate-mapping>
CalendarEvent:
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by NHibernate.Mapping.Attributes on 2009-10-09 18:27:46Z.-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Calendar.CalendarEvent, Calendar" table="CalendarEvents">
<id name="CalendarEventId" column="CalendarEventId" type="Int32">
<generator class="native" />
</id>
<property name="EventStatus" />
<property name="StartTime" />
<property name="EndTime" />
<property name="ImageUrl" length="255" />
<property name="Description" length="2000" />
<property name="LocationName" length="255" />
<property name="Address1" length="255" />
<property name="Address2" length="255" />
<property name="City" length="255" />
<property name="State" length="255" />
<property name="Zip" length="10" />
<property name="Title" length="255" />
<property name="Url" length="255" />
<property name="ExternalSystemId" />
<property name="ExternalSystem" type="Calendar.GenericEnumMapper`1[[Calendar.ExternalSystemType, Calendar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Calendar" length="50" />
<property name="RecordCreatedBy" column="CreatedBy" length="50" />
<property name="RecordModifiedBy" column="ModifiedBy" length="50" />
<property name="CreateDate" />
<property name="ModifiedDate" />
<many-to-one name="ParentEvent" column="ParentEventId" />
<bag name="ChildEvents" lazy="true" fetch="subselect" cascade="all" inverse="true">
<key column="ParentEventId" />
<one-to-many class="Calendar.CalendarEvent, Calendar" />
</bag>
<bag name="Calendars" table="CalendarEventsInCalendar" lazy="false" inverse="true">
<key column="CalendarEventId" />
<many-to-many class="Calendar.Calendar, Calendar" column="CalendarId" />
</bag>
</class>
</hibernate-mapping>
And here's how I add an Event to a Calendar:
public virtual void AddEvent(CalendarEvent calEvent)
{
if(!calEvent.Calendars.Contains(this))
calEvent.Calendars.Add(this);
Events.Add(calEvent);
}
Then I do a SaveOrUpdate(calendar)
Any ideas?

You have to wrap the SaveOrUpdate in a transaction and then do Transaction.Commit(). Otherwise, the Mapping doesn't save, only the entities.
Thanks,
Jason

I think the problem is in inverse=true for CalendarEvent. You should remove it

Related

Why will NHibernate not use 2nd level cache on second request?

I have the following model.
<class name="Navigation" table="`navigation`">
<cache usage="nonstrict-read-write" region="LongTerm" />
<id name="Id" column="`navigation_id`" type="Int16" unsaved-value="0">
<generator class="native" />
</id>
<property name="Name" column="`navigation_name`" type="String" not-null="true" />
<property name="DateCreated" column="`navigation_date-created`" type="DateTime" not-null="true" />
<property name="DateSaved" column="`navigation_date-saved`" type="DateTime" not-null="true" />
<property name="Active" column="`navigation_active`" type="Boolean" not-null="true" />
<property name="RestrictToWebMaster" column="`navigation_web-master-restrict`" type="Boolean" not-null="true" />
<many-to-one name="User" column="user_id" class="User" />
<set name="Items" order-by="`navigation-item_index` asc" inverse="true" cascade="all-delete-orphan">
<cache usage="nonstrict-read-write" region="LongTerm" />
<key column="`navigation_id`" />
<one-to-many class="Navigation+Item" />
</set>
</class>
Then I have a test.aspx that querys a collection.
DataProvider provider = new DataProvider(SessionManager.GetSession());
protected void Page_Load(object sender, EventArgs e)
{
IList<Navigation> navs = provider.Session.QueryOver<Navigation>()
.Cacheable()
.List();
foreach (Navigation nav in navs) {
litTest.Text += nav.Name + "<br />";
}
}
When, I reload the page the query is re-run. Why isn't the data retrieved from cache?
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2-x-factories">
<session-factory name="Default">
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="current_session_context_class">web</property>
<property name="show_sql">true</property>
<property name="cache.provider_class">NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache</property>
<property name="cache.use_query_cache">true</property>
<property name="cache.use_second_level_cache">true</property>
</session-factory>
</hibernate-configuration>
<syscache>
<cache region="LongTerm" expiration="3600" priority="5" />
<cache region="MediumTerm" expiration="900" priority="3" />
<cache region="ShortTerm" expiration="180" priority="1" />
</syscache>
You should run this in a transaction and commit the transaction at the end.
NHibernate updates the 2nd level cache only if the transaction has been committed successfully. If you don't start a NHibernate transaction, NHibernate will not know if the results are good enough to be cached.

Why Aren't Deletes Cascading With This NHibernate Configuration File?

I have the below NHibernate file, however I am not allowed to delete a Question because of a foreign key constraint on either of the two Answer tables. The desired behavior is to delete Answers once corresponding Questions are deleted and cascade settings are set on the Answers element.
Below is the configuration file, can anyone see what the problem is
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="Test.Domain" assembly="Test.Domain" xmlns="urn:nhibernate-mapping-2.2">
<class name="Question" abstract="true">
<id name="Id" type="Int32">
<generator class="hilo" />
</id>
<discriminator />
<property name="Text" length="500" />
<property name="Note" length="2000" />
<property name="DateRun" />
<many-to-one name="ChoiceType" column="ChoiceTypeId" />
<bag name="Answers" inverse="true" cascade="all,delete-orphan">
<key column="QuestionId" on-delete="cascade" />
<one-to-many class="Answer" />
</bag>
</class>
<class name="Answer" abstract="true">
<id name="Id" type="Int32">
<generator class="hilo" />
</id>
<many-to-one name="Question" column="QuestionId" />
<many-to-one name="Group" column="GroupId" />
<property name="Comment" />
</class>
<class name="Choice">
<id name="Id" type="Int32">
<generator class="hilo" />
</id>
<property name="Text" length="500" />
</class>
<class name="ChoiceType">
<id name="Id" type="Int32">
<generator class="hilo" />
</id>
<property name="Name" />
<property name="Type" />
<list name="Choices" cascade="all,delete-orphan">
<key column="ChoiceTypeId" />
<list-index column="ChoicesPos" />
<one-to-many class="Choice" />
</list>
</class>
<class name="Division">
<id name="Id" type="Int32">
<generator class="hilo" />
</id>
<property name="Name" />
</class>
<union-subclass name="FreeTextAnswer" extends="Answer">
<property name="Text" length="500" />
</union-subclass>
<union-subclass name="MultipleChoiceAnswer" extends="Answer">
<many-to-one name="Choice" column="ChoiceId" />
</union-subclass>
<subclass name="MultipleChoiceQuestion" extends="Question" />
<subclass name="FreeTextQuestion" extends="Question" />
</hibernate-mapping>
Isn't it
cascade="all-delete-orphan"
... with a hyphen, as opposed to two enum values?
Your answers collection mapping should look like this:
<bag name="Answers" inverse="true" cascade="all-delete-orphan">
<key column="QuestionId"/>
<one-to-many class="Answer" />
</bag>
I removed on-delete="cascade". When you you want to remove one answer from the question you will have to 'chase pointers'. Set reference to question to NULL, in addition to removing it from answers collection:
answer.Question = null;

NHibernate AssertException: Interceptor.OnPrepareStatement(SqlString) returned null or empty SqlString

I am trying to switch a table from being a many-to-one mapping to being many-to-many with an intermediate mapping table. However, when I switched it over and tried to do a query on it with NHibernate, it's giving me this error: "Interceptor.OnPrepareStatement(SqlString) returned null or empty SqlString."
My query was originally something more complex, but I switched it to a basic fetch all and I'm still having the problem:
Session.QueryOver<T>().Future();
It would seem to either be a problem in my model mapping files or something in my database.
Here are my model mappings:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="GBI.Core" namespace="GBI.Core.Models">
<class name="Market" table="gbi_Market">
<id name="Id" column="MarketId">
<generator class="identity" />
</id>
<property name="Name" />
<property name="Url" />
<property name="Description" type="StringClob" />
<property name="Rating" />
<property name="RatingComment" />
<property name="RatingCommentedOn" />
<many-to-one name="RatingCommentedBy" column="RatingCommentedBy" lazy="proxy"></many-to-one>
<property name="ImageFilename" />
<property name="CreatedOn" />
<property name="ModifiedOn" />
<property name="IsDeleted" />
<many-to-one name="CreatedBy" column="CreatedBy" lazy="proxy"></many-to-one>
<many-to-one name="ModifiedBy" column="ModifiedBy" lazy="proxy"></many-to-one>
<set name="Content" where="IsDeleted=0 and ParentContentId is NULL" order-by="Ordering asc, CreatedOn asc, Name asc" lazy="extra">
<key column="MarketId" />
<one-to-many class="MarketContent" />
</set>
<set name="FastFacts" where="IsDeleted=0" order-by="Ordering asc, CreatedOn asc, Name asc" lazy="extra">
<key column="MarketId" />
<one-to-many class="MarketFastFact" />
</set>
<set name="NewsItems" table="gbi_NewsItem_Market_Map" lazy="true">
<key column="MarketId" />
<many-to-many class="NewsItem" fetch="join" column="NewsItemId" where="IsDeleted=0"/>
</set>
<!--<set name="MarketUpdates" table="gbi_Market_MarketUpdate_Map" lazy="extra">
<key column="MarketId" />
<many-to-many class="MarketUpdate" fetch="join" column="MarketUpdateId" where="IsDeleted=0" order-by="CreatedOn desc" />
</set>-->
<set name="Documents" table="gbi_Market_Document_Map" lazy="true">
<key column="MarketId" />
<many-to-many class="Document" fetch="join" column="DocumentId" where="IsDeleted=0"/>
</set>
</class>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="GBI.Core" namespace="GBI.Core.Models">
<class name="MarketUpdate" table="gbi_MarketUpdate">
<id name="Id" column="MarketUpdateId">
<generator class="identity" />
</id>
<property name="Description" />
<property name="CreatedOn" />
<property name="ModifiedOn" />
<property name="IsDeleted" />
<!--<many-to-one name="Market" column="MarketId" lazy="proxy"></many-to-one>-->
<set name="Comments" where="IsDeleted=0" order-by="CreatedOn desc" lazy="extra">
<key column="MarketUpdateId" />
<one-to-many class="MarketUpdateComment" />
</set>
<many-to-one name="CreatedBy" column="CreatedBy" lazy="proxy"></many-to-one>
<many-to-one name="ModifiedBy" column="ModifiedBy" lazy="proxy"></many-to-one>
</class>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="GBI.Core" namespace="GBI.Core.Models">
<class name="MarketUpdateMarketMap" table="gbi_Market_MarketUpdate_Map">
<id name="Id" column="MarketUpdateMarketMapId">
<generator class="identity" />
</id>
<property name="CreatedOn" />
<property name="ModifiedOn" />
<property name="IsDeleted" />
<many-to-one name="CreatedBy" column="CreatedBy" lazy="proxy"></many-to-one>
<many-to-one name="ModifiedBy" column="ModifiedBy" lazy="proxy"></many-to-one>
<many-to-one name="MarketUpdate" column="MarketUpdateId" lazy="proxy"></many-to-one>
<many-to-one name="Market" column="MarketId" lazy="proxy"></many-to-one>
</class>
As I mentioned, MarketUpdate was originally a many-to-one with Market (MarketId column is still in there, but I'm ignoring it. Could this be a problem?). But I've added in the Market_MarketUpdate_Map table to make it a many-to-many.
I'm running in circles trying to figure out what this could be. I couldn't find any reference to this error when searching. And it doesn't provide much detail.
Using:
NHibernate 2.2
.NET 4.0
SQL Server 2005
Turns out the problem was just that the xml mapping file was set as content instead of embedded resource in visual studio. Changing that fixed all my problems.
If you're using Fluent rather than xml for mappings and encounter this issue, try deleting the generated xml files in %root%\LocalCache\NHibernate.

"many-to-one" within component problem NHibernate

With the following mapping, BillingAddress.Country is mapped correctly but ShippingAddress.Country is always null. Maybe it's because of equal properties name? but they are different objects... Any idea how to fix it?
Thanks ahead.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="KapsNet.QuickOffice.Models" namespace="KapsNet.QuickOffice.Dto">
<class name="Order" table="`Order`" >
<id name="ID" type="System.Int32" column="ID">
<generator class="identity"/>
</id>
<property name="CreateDate" column="CreateDate" type="System.DateTime" not-null="true" />
<property name="ClientContactID" column="ClientContactID" type="System.Int32" not-null="true" />
<component name="BillingAddress" class="AddressInfo">
<property name="Address" column="BillingAddress" type="System.String" not-null="false" length="255"/>
<property name="ZipCode" column="BillingZipCode" type="System.String" not-null="false" length="50"/>
<property name="City" column="BillingCity" type="System.String" not-null="false" length="50"/>
<property name="CountryID" column="BillingCountryID" type="System.Int32" not-null="true" />
<property name="Phone" column="BillingPhone" type="System.String" not-null="false" length="50"/>
<many-to-one name="Country" column="BillingCountryID" class="Country" update="0" insert="0" />
</component>
<component name="ShippingAddress" class="AddressInfo">
<property name="Address" column="ShippingAddress" type="System.String" not-null="false" length="255"/>
<property name="ZipCode" column="ShippingZipCode" type="System.String" not-null="false" length="50"/>
<property name="City" column="ShippingCity" type="System.String" not-null="false" length="50"/>
<property name="CountryID" column="ShippingCountryID" type="System.Int32" not-null="true" />
<property name="Phone" column="ShippingPhone" type="System.String" not-null="false" length="50"/>
<many-to-one name="Country" column="ShippingCountryID" class="Country" update="0" insert="0" />
</component>
<many-to-one name="ClientContact" column="ClientContactID" class="ClientContact" update="0" insert="0" />
<bag name="OrderItemList" table="OrderItem" inverse="true" lazy="true" cascade="delete">
<key column="OrderID" />
<one-to-many class="OrderItem"/>
</bag>
</class>
</hibernate-mapping>
You should remove CountryID from the mappings for billing and shipping address because it is already defined in the many-to-one relationship to Country. Other than that the mappings look okay. Components will be null if all of the values in the component are null. So, if all of the shipping address fields are null then the ShippingAddress component will be null.

Many to one mapping problem with NHibernate

Firstly I am relatively new to NHibernate. Got two tables on TaxMapping and Address. A single TaxMapping must have one address and one address can belong to more than one Tax Mapping. They are linked through foreign key
TaxMapping hbm
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ITAPDTO" assembly="ITAPDTO">
<class name="TaxMapping" table="tblTaxMapping">
<id name="Tax_Mapping_ID">
<column name="Tax_Mapping_ID" sql-type="bigint" not-null="true"/>
<generator class="identity" />
</id>
<property name="Tax_ID" />
<property name="Client_Code" />
<property name="NRA_Sub_Account" />
<property column="Domicile" type="String" name="Domicile" length="5" />
<many-to-one name="Address" column="AddressID" cascade="none" not-found="exception" not-null="true" fetch="join" class="ITAPDTO.Address,ITAPDTO" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ITAPDTO" assembly="ITAPDTO">
<class name="Address" table="Address">
<id name="AddressID" column="AddressID" type="Int32" unsaved-value="0">
<generator class="identity"/>
</id>
<property column="Client" type="String" name="Client" not-null="true" length="100" />
<property column="Contact" type="String" name="Contact" not-null="true" length="50" />
<property column="Address1" type="String" name="Address1" not-null="true" length="100" />
<property column="Address2" type="String" name="Address2" not-null="true" length="100" />
<property column="Address3" type="String" name="Address3" not-null="true" length="100" />
<property column="City" type="String" name="City" not-null="true" length="50" />
<property column="State" type="String" name="State" not-null="true" length="50" />
<property column="PoBox" type="String" name="PoBox" not-null="true" length="50" />
<property column="PostCode" type="String" name="PostCode" not-null="true" length="20" />
<property column="Country" type="String" name="Country" not-null="true" length="50" />
<property column="InsertedBy" type="String" name="Modified_By" length="20" />
<property column="InsertedOn" type="DateTime" name="Modified_Date" />
<property column="ConfirmedBy" type="String" name="Approved_By" length="20" />
<property column="ConfirmedOn" type="DateTime" name="Approved_Date" />
<property column="Status" type="String" name="Status" />
<property column="IUD" type="String" name="IUD" />
</class>
</hibernate-mapping>
I can pull in the data and bind to grid view with no issue. However when I update the Taxmapping the AddressID for the Address oject is always null event thoughh the other address fields are correctly populated and I dont know why. I currently have a hack in place the pulls the id from the db before I call update but I really shouldn't have to do this. Any thoughts would be welcome
regards
Is this due to cascade being set to "none" on the Taxmapping object's Address property? Try changing it to "save-update". You may also want to read the nhibernate documentation to figure out which cascade setting would be best for your situation, though it sounds like "save-update" would be most appropriate.
In addition to Krazzy's point, you should also check that your sessions are closed and / or flushed appropriately. A long-running session which is never flushed can exhibit similar problems.