I am using FluentNHibernate with my application and I have run into an issue in my application.
Following is the class structure
namespace Project.Core.Models
{
public class Country
{
public virtual int CountryID { get; set; }
public virtual string Name { get; set; }
public virtual string ISOCountryCode { get; set; }
public virtual string InternationalCallingCode { get; set; }
}
public class CustomerAddress
{
public virtual int CustomerAddressID { get; set; }
public virtual string Street { get; set; }
public virtual string TownOrCity { get; set; }
public virtual string County { get; set; }
public virtual string Postcode { get; set; }
public virtual Country Country { get; set; }
public virtual Customer Customer { get; set; }
}
public class Customer
{
public virtual int CustomerID { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual bool IsActive { get; set; }
//Customer can have more than one addresses
public virtual IList<CustomerAddress> Addresses { get; set; }
}
}
Following are the FluentMappings
public class CountryMap : ClassMap<Country>
{
public CountryMap()
{
Id(x => x.CountryID);
Map(x => x.Name);
Map(x => x.ISOCountryCode);
Map(x => x.InternationalCallingCode);
Table("tblCountry");
}
}
public class CustomerAddressMap : ClassMap<CustomerAddress>
{
public CustomerAddressMap()
{
Id(x => x.CustomerAddressID);
Map(x => x.Street);
Map(x => x.TownOrCity);
Map(x => x.County);
Map(x => x.Postcode);
References(x => x.Country)
//.Not.LazyLoad()
.Cascade.All();
References(x => x.Customer);
//.Not.LazyLoad();
Table("tblCustomerAddress");
}
}
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.CustomerID);
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.IsActive);
HasMany(x => x.Addresses)
//.Not.LazyLoad()
.Inverse()
.Cascade.All();
Table("tblCustomer");
}
}
In my application I have already created the customer but no addresses added. I have created an screen for adding/updating customers and their addresses.
The screen has two text boxes for first and the last names and a checkbox for IsActive status. Also there is a datagrid to add and update customer addresses.
The datagrid has a combobox column for country and textbox columns for other fields.
- The country combobox of the datagrid is populated with the countries in the country table of database.
My problem is when adding addresses to already created customers. (also I haven't figure out how to add a address for a new customer as well)
After I type in an address details in the grid and select a country, I hit the save button expecting the NHibernate to save data to the corresponding tables and link the newly added address to current customer.
When I check the customer object sent NHibernate for saving, it has got an address added to the Addresses IList but the Customer property of the newly added CustomerAddress instance is NULL. Since I do not have much experience with NHibernate/FluentNHibernate, I thought that upon saving NHibernate will update the Customer for Customer address.
The address was saved to the database without adding a reference to customer.
However when I look at the SQL output generated, I cannot see any statements updating the newly added customer address with the correct customer ID. Instead it generates and update statement for updating Country, which is not needed.
Below is the SQL output generated by NHibernate.
NHibernate:
INSERT INTO tblCustomerAddress (Street, TownOrCity, County, Postcode, Country_id, Customer_id)
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
@p0 = 'Street 1' [Type: String (0)], @p1 = 'Town 1' [Type: String (0)], @p2 = 'County 1' [Type: String (0)], @p3 = '123' [Type: String (0)], @p4 = 2 [Type: Int32 (0)], @p5 = NULL [Type: Int32 (0)]
NHibernate: select @@IDENTITY
NHibernate:
UPDATE tblCountry SET Name = @p0, ISOCountryCode = @p1, InternationalCallingCode = @p2 WHERE CountryID = @p3;
@p0 = 'United Kingdom' [Type: String (0)], @p1 = 'GBP' [Type: String (0)], @p2 = '+44' [Type: String (0)], @p3 = 2 [Type: Int32 (0)]
There is no need to update the country table as that is just a reference table I am using to get the correct country.
Instead it should update the newly added customer address with correct customerID. I cannot figure out what is happening in my code and I am not sure if I have correctly specified the relationships.
It would be a great help if someone can help me fixing this.
Thanks.....
NHibernate mappings once exported using ExportTo() function.
Country.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="Project.Core.Models.Country, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="tblCountry">
<id name="CountryID" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="CountryID" />
<generator class="identity" />
</id>
<property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Name" />
</property>
<property name="ISOCountryCode" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ISOCountryCode" />
</property>
<property name="InternationalCallingCode" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="InternationalCallingCode" />
</property>
</class>
</hibernate-mapping>
Customer.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="Project.Core.Models.Customer, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="tblCustomer">
<id name="CustomerID" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="CustomerID" />
<generator class="identity" />
</id>
<bag cascade="all" inverse="true" name="Addresses">
<key>
<column name="Customer_id" />
</key>
<one-to-many class="Project.Core.Models.CustomerAddress, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
<property name="FirstName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="FirstName" />
</property>
<property name="LastName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="LastName" />
</property>
<property name="IsActive" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="IsActive" />
</property>
</class>
</hibernate-mapping>
CustomerAddress.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="Project.Core.Models.CustomerAddress, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="tblCustomerAddress">
<id name="CustomerAddressID" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="CustomerAddressID" />
<generator class="identity" />
</id>
<property name="Street" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Street" />
</property>
<property name="TownOrCity" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="TownOrCity" />
</property>
<property name="County" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="County" />
</property>
<property name="Postcode" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Postcode" />
</property>
<many-to-one class="Project.Core.Models.Country, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Country">
<column name="Country_id" />
</many-to-one>
<many-to-one cascade="all" class="Project.Core.Models.Customer, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Customer">
<column name="Customer_id" />
</many-to-one>
</class>
</hibernate-mapping>
CustomerAddress.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="Project.Core.Models.CustomerAddress, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="tblCustomerAddress">
<id name="CustomerAddressID" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="CustomerAddressID" />
<generator class="identity" />
</id>
<property name="Street" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Street" />
</property>
<property name="TownOrCity" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="TownOrCity" />
</property>
<property name="County" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="County" />
</property>
<property name="Postcode" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Postcode" />
</property>
<many-to-one class="Project.Core.Models.Country, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Country">
<column name="Country_id" />
</many-to-one>
<many-to-one cascade="all" class="Project.Core.Models.Customer, Project.Core.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Customer">
<column name="Customer_id" />
</many-to-one>
</class>
</hibernate-mapping>
ExportTowhen you build your configuration and post the HBM mappings somewhere? - Rippo