NHibernate mapping child to multiple possible parent - nhibernate

I have this Address table like below:
Address
-------
ID (pk)
OWNERTYPE (int)
OWNERID (int)
ADDR1
ADDR2
....
this is a "child" table, where it would be mapped to any possible "parent" table. To discriminate which parent table it has relation to, it has the column "ONWERTYPE". "OWNERTYPE" will store the identifier which parent table it relates to, while "OWNERID" will hold the primary key of the parent table (this is Foreign key column).
how do i map this relation with the parent table?
p/s:
the parent table do not have any
column that indicates its relation to
the child.
the parent tables have their own entities that represent them

You need to use an <any> mapping, as explained here.

I have found another solution but I need advice whether I'm doing the correct way.
The database tables itself is not design by me, thus I cant help but to follow the structure.
because all of the address data is stored only in one table, I use an inheritance mapping to do this.
for example i have 3 tables like this;
Address table
Address
-------
ID (pk)
ownertype (string)
ownerid (int)
addr1
postcode
...
User table
User
-----
ID (pk)
name
...
Org table
Org
----
ID (pk)
Orgname
....
according to my DBA, she said that both User and Org table has relation to the address table, and it is differentiated by the ownertype column in the address table.
so, I made the one base entity "Address" that has all the common properties like this:
public abstract class Address {
public virtual string addr1 { get;set; }
public virtual int postcode { get;set; }
...
}
then for each parent table relation to the address table, I made another subclass of address (derived from class Address) and made so that parent entity relationship to this subclass instead of the Address class, like so:
UserAddress subclass of Address
public class UserAddress : Address {
public virtual User Owner { get;set; }
}
User entity
public class User {
public virtual int ID { get;set; }
public virtual string Name { get;set; }
public virtual UserAddress Address {
get {
return address;
}
set {
if (value != null)
value.Owner = this
address = value
}
}
}
and the mapping for Adderss, UserAddress and user is like the following:
Address and its subclasses (Table per class hierarchy strategy):
<class name="Address" table="Address" abstract="true">
<id name="ID">
<generator class="identity"/>
</id>
<discriminator column="Ownertype" type="System.String" />
<property name="addr1 />
<property name="postcode" />
....
<subclass name="UserAddress" discriminator-value="USER">
<many-to-one name="Owner" column="Ownerid" />
</subclass>
<subclass name="OrgAddress" discriminator-value="ORG">
<many-to-one name="Owner" column="Ownerid" />
</subclass>
</class>
User:
<class name="User" table="User">
<id name="ID">
<generator class="identity"/>
</id>
<property name="Name" />
....
<one-to-one name="Address" property-ref="Owner" cascade="all" />
</class>
is this the correct way to do this? do give me any other better alternative than this.
notes: i do not show here on Org entity and mapping, basically it has the same concept as user table. pardon me for any syntax error as I type this here, because the real entity name is not intuitive without docs to refer.

Related

NHibernate one-to-one mapping - full object graph is not saved

I am trying to get NHibernate to save complete object graph in a one-to-one mapping scenario. I have following classes
public class Employee : EntityBase
{
public virtual string EmployeeNumber { get; set; }
public virtual Address ResidentialAddress {get; set; }
}
public class Address : EntityBase
{
public virtual string AddressLine1 { get; set; }
public virtual string AddressLine2 { get; set; }
public virtual string Postcode { get; set; }
public virtual string City { get; set; }
public virtual string Country { get; set; }
public virtual Employee Employee { get; set; }
}
I am trying to use one-to-one mapping here so that one employee has only one residential address. My mappings are below
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
<class name="Employee">
<id name="Id" generator="hilo" />
<property name="EmployeeNumber" length="10" />
<one-to-one name="ResidentialAddress" class="Address" property-ref="Employee" cascade="all" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
<class name="Address">
<id name="Id" generator="hilo" />
<property name="AddressLine1"/>
<property name="AddressLine2" />
<property name="Postcode" />
<property name="City" />
<property name="Country" />
<many-to-one name="Employee" class="Employee" unique="true" />
</class>
</hibernate-mapping>
I am using following code to save an instance of employee object
using (var transaction = Session.BeginTransaction())
{
id = Session.Save(new Employee
{
EmployeeNumber = "123456789",
ResidentialAddress = new Address
{
AddressLine1 = "Address line 1",
AddressLine2 = "Address line 2",
Postcode = "postcode",
City = "city",
Country = "country"
}
});
transaction.Commit();
}
In the above situation, the foreign key on Address back to Employee is always null. But if I change RResidentialAddress property on Employee class so that Employee property is always populated correctly as below
private Address address;
public virtual Address ResidentialAddress
{
get { return address; }
set
{
address = value;
if (value != null) value.Employee = this;
}
}
This makes it work perfectly. Why do I have to set ResidentialAddress.Employee? Am I missing something in the mappings? Should NHibernate not automatically save the complete object graph (and hence determine proper foreign key values).
The above working code concerns me as it may create a problem when called from NHiberante during loading of entity from database.
Your are not missing anything.
We (developers) should always care about setting both ends of any bidirectional relation.
When we use one-to-many (without inverse="true") and without setting the many-to-one, we always end up with redundant and unefficient sequence of SQL statements:
INSERT child record, place NULL into Parent_ID
UPDATE child record, set the Parent_ID with Parent.ID
This is not suggested: 6.8. Bidirectional Associations:
... The non-inverse side is used to save the in-memory representation to the database. We would get an unneccessary INSERT/UPDATE and probably even a foreign key violation if both would trigger changes! The same is of course also true for bidirectional one-to-many associations...
So, that is in one-to-many, many-to-one.
In case of one-to-one
There is no collection persister in place as discussed above. No man in the middle, which would take care about the other end, and issue "unefficient" INSERT and later UPDATE. NHibernate will use standard entity persisters for Employee and Address.
Each association end of the relation (Employee-Address) has its own persister. These could be triggered in a cascade (usually good idea to have <one-to-one ... cascade="all" />)
But each persister needs enough information to create proper INSERT or UPDATE statement. I.e. even C# Address must know about its Employee. The Address persister, will handle INSERT/UPDATE alone, with access to Address instance only.
SUMMARY: We have to set both ends in code.... And that is good practice even if we are not forced (non inverse child mapping with nullable parent column).
BTW: once loaded from DB, we expect that NHibernate will set both ends... why should not we do the same?

nhibernate many-to-one parent is always null on insert

I am using NHibernate 3.1.0.4000 and AutoMapper 2.0.0.0 in a WCF. I have a parent-child relationship I want to maintain from the "many" end. I have no problems maintaining the objects if I do it from the "one" end but in this case that does not make sense. My issue is no matter how I change my mappings, POCOs, etc. the parent object when I attempt to add a child is null in the child causing the insert to fail. What am I missing to get the parent property in the child to populate?
I have a parent-child relationship defined in the following tables:
Create Table Attribute (AttributeUID uniqueidentifier, LongName varchar(20))
Create Table AnswerOption (AnswerOptionID int, AttributeUID uniqueidentifier)
I want the Attribute (parent) to be the owner so I declare the relationship in that mapping file and not in the AnswerOption (child). Though, I have tried with having the relationship bidirectional as well and that has not changed any behaviors in my tests. My mappings apear as follows. Attribute:
<class name="RCAttribute" table="rcs.tblAttribute">
<cache usage="read-write"/>
<id name="ID">
<column name="AttributeUID" />
<generator class="guid" />
</id>
<property name="LongName" type="string" not-null="true" length="200" column="LongName" />
<bag name="AnswerOptions" lazy="true" inverse="true" cascade="all">
<key column="AttributeUID"/>
<one-to-many class="AnswerOption" />
</bag>
</class>
AnswerOption:
<class name="AnswerOption" table="rcs.tblAnswerOption" lazy="true">
<cache usage="read-write"/>
<id name="ID">
<column name="AnswerOptionID" />
<generator class="native" />
</id>
</class>
Attribute Class:
[Serializable]
public class RCAttribute
{
public virtual Guid ID { get; set; }
public virtual string LongName { get; set; }
public virtual ICollection<AnswerOption> AnswerOptions { get; set; }
public RCAttribute() { ID = new Guid("00000000-0000-0000-0000-000000000000"); }
}
AnswerOption Class:
[Serializable]
public class AnswerOption
{
public virtual int ID { get; set; }
public AnswerOption() { ID = 0; }
}
My test procedure looks like this;
public void CreateAnswerOption()
{
AnswerOption newOpt = new AnswerOption();
Attribute.AnswerOptions.Add(newOpt);
Attribute = rc.RCAttributeSave(Attribute);
}
When it goes to create this the Attribute property of the AnswerOption is null so it cannot insert since the parent cannot be null in the child in this case. What am I missing to get it to populate the parent property on the child and be able to insert?
Mapping the collection as inverse without mapping the many-to-one on the other side makes no sense.
You have three options:
Use a bidirectional mapping with inverse="true" on the collection side and set the many-to-one propery (parent reference) in your code before saving the child (yes, I read that you don't want to do it that way).
Only map the collection side (not inverse). NHibernate will then first insert the child with NULL as parent reference, but will update it with the correct parent ID in the same transaction. So you can't have a not null constraint on the parent ID column in the child table (at least it must be deferrable).
(This option only works with NHibernate 3.2.0 or newer) Same as option 2, but add not-null="true" to the key tag in the collection mapping. Then NHibernate will insert the child with the parent ID already set.

NHibernate Mapping for class contained by multiple classes

I have a problem in NHibernate mapping.
I have Class Company, Person and Address; Company and Person both can have Addresses hence i have taken Address in both. To store this I have tables Company, Person and Address. Now Company will have Address object and Person will also have Address Object so Address should also have reference to Company and Person object. So I created two child classes of Address 1. CompanyAddress 2. PersonAddress and in Database I created two more tables Company_Address and Person_Address. Now In Address.hbm.xml i have added Joined subclass for both CompanyAddress and PersonAddress which are referring to Company_Address and Person_Address tables respectively.
Now CompanyAddress class is having company object in it and PersonAddress class is having Person object in it.
Company_Address is having 2 columns AddressId(PK) and CompanyId(FK)->Company
Person_Address is having 2 columns AddressId(PK) and PersonId(FK)->Person
I have created one-to-one mapping in Company.hbm.xml for Address.
When i Save Company object every table is populating properly except Company_Address.
AddressId is getting stored but CompanyId is not getting stored.
I have no idea how to get this working
If someone can faced this problem please help.
Thanks in advance!!!
Pawan Shukla
It sounds like you may have over-normalized here, given that you have set up one-to-one mappings. What might be easier (and WAY cleaner in code) is to place your address fields in the Company and Person tables themselves, then set up a simple address object and treat it as a component. Here's my address class:
public class StreetAddress
{
public string CountryCode { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string County { get; set; }
public string StateCode { get; set; }
public string PostalCode { get; set; }
public StreetAddress()
{
// Constructor for NHibernate
}
public StreetAddress(string countryCode, string street, string city, string county, string stateCode, string postalCode)
{
CountryCode = countryCode;
Street = street;
City = city;
County = county;
StateCode = stateCode;
PostalCode = postalCode;
}
}
Then you treat the address as a component, and map it like this:
<component name="Address" insert="true" update="true" optimistic-lock="true">
<property name="CountryCode">
<column name="Address_CountryCode" />
</property>
<property name="Street">
<column name="Address_Street" />
</property>
<property name="City">
<column name="Address_City" />
</property>
<property name="County">
<column name="Address_County" />
</property>
<property name="StateCode">
<column name="Address_StateCode" />
</property>
<property name="PostalCode">
<column name="Address_PostalCode" />
</property>
</component>
Don't do it this way. Address is clearly not an entity (and hence has no table of it's own and no primary key). What I would rather do is to model it as a component. A sample mapping might look like this:
<class name="Company"
table="Company">
<id name="Id">
<generator class="identity"/>
</id>
<property name="CompanyName" />
<component name="Address">
<property name="Street"/>
<property name="HouseNumber"/>
<property name="City"/>
<property name="PostOffice"/>
</component>
</class>
Just google a bit. In DDD there's a notion of a value object opposed to an entity, and the way to model value objects in NHibernate is to use components.

NHibernate Map many-to-many join table

My database structure looks something like this:
Person
Id
Name
FieldA
FieldB
Phone
Id
Number
PersonPhone
PhoneId
PersonId
IsDefault
My NHibernate mappings for the Person and Phone objects are straight forward, its the PersonPhone I'm having difficult with. I want to have a collection of PersonPhone objects as a property of Person which will allow me to have the Phone number of a person and be able to tell which is the "default" or primary phone number for a person.
ideally Id like my PersonPhone object to look like this:
public class PersonPhone
{
public virtual Person Person { get; set; }
public virtual Phone Phone { get; set; }
public virtual bool IsDefault { get; set; }
}
so far my NHibernate mapping for this table looks like the following:
<class name="PersonPhone" table="PersonPhone">
<composite-id>
<key-property name="Person" column="PersonId" />
<key-property name="Phone" column="PhoneId" />
</composite-id>
<property name="IsDefault" column="IsDefault"/>
</class>
but when NHibernate compiles my mappings I get an error saying:
Could not compile the mapping document: MyApp.Entities.PersonPhone.hbm.xml. NHibernate.MappingException : Could not determine type for: MyApp.Entities.Person, MyApp.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(PersonId)
Any ideas on how this should be mapped?
The answer is to use the element in your composite key rather than the key-property
<class name="PersonPhone" table="PersonPhone">
<composite-id>
<key-many-to-one name="Person" column="PersonId"></key-many-to-one>
<key-many-to-one name="Phone" column="PhoneId"></key-many-to-one>
</composite-id>
<property name="IsDefault" column="IsDefault"/>
</class>
I think It is more proper to consider Many-to-Many relationship between Phone and Peron entities and get rid of PersonPhone entity.
To set-up the same mapping with Fluent NHibernate, do this:
public class PersonPhoneMap : ClassMap<PersonPhone>
{
public PersonPhoneMap()
{
CompositeId()
.KeyReference(p => m.Person)
.KeyReference(p => m.Phone);
References(p => p.Person)
.Column("PersonID");
References(m => m.Phone)
.Column("PhoneID");
Map(p => p.IsDefault)
.Column("IsDefault");
}
}

Lazy loading not working for many-to-one relationship when mapping to a non-key field using property-ref

I have a legacy database that I am mapping using NHibernate. The objects of concern are an Account and a list of Notification objects. The objects look like:
public class Notification
{
public virtual int Id { get; set; }
public virtual DateTime BatchDate { get; set; }
/* other properties */
public virtual Account Account { get; set; }
}
public class Account
{
public virtual int Id { get; set; }
public virtual string AccountNumber { get; set; }
/* other properties */
}
The mapping files look like:
<class name="Account" table="Account" dynamic-update="true">
<id name="Id" column="AccountID">
<generator class="native" />
</id>
<property name="AccountNumber" length="15" not-null="true" />
<!-- other properties -->
</class>
<class name="Notification" table="Notification">
<id name="Id" column="Id">
<generator class="native" />
</id>
<!-- other properties -->
<many-to-one name="Account" class="Account" property-ref="AccountNumber" lazy="proxy">
<column name="AcctNum" />
</many-to-one>
However, when I create a criteria such as
return session.CreateCriteria(typeof(Notification)).List<Notification>();
I am getting a Select N+1 case where each account is loaded even though the Account is never referenced. Why are all of the accounts getting loaded when the many-to-one is mapped as a lazy proxy?
The issue is caused by the property-ref attribute. Lazy loading only works when the many-to-one reference is using the other object's primary key since NHibernate assumes there's a foreign key constraint enforcing the validity of such a value. With a non-primary key (indicated by the property-ref), NHibernate does not make this assumption and thus does not assume the related object must exist. Since it does not want to create a proxy for an object that does not exist (i.e. should be null instead of a proxy), it eagerly fetches the remote object. This same issue exists when not-found="ignore" is specified since this indicates that the foreign key relationship is not enforced and may result in a null reference.
See also:
NHibernate creates proxy via session.Load(), but not via Linq or Criteria API
http://frankmao.com/2007/12/05/lazy-load-conflicts-with-property-ref-in-many-to-one-mapping/