I have a true one to one mapping. But I would like to use lazy loading(load on demand).
I have Class Person with a association with Class Address. The mapping looks like this..
PERSON
<one-to-one name="address" class="Person" cascade="all-delete-orphan" access="field">
ADDRESS
<class name="Address" table="Address" lazy="true">
<id name="id" column="addressId" type="Int32" access="field">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person" class="Address" constrained="true" access="field" />
Does anyone see something wrong with this? How do I enable proxy/lazy loading for address?
Thanks
Heres a good discussion on the topic http://ayende.com/Blog/archive/2007/05/10/NHibernate-onetoone.aspx
Crucial quote: "In other words, one-to-one cannot be lazily loaded, which is one of the reasons why it is recommended to use two many-to-one instead."
Also see https://www.hibernate.org/162.html and NHibernate: how to enable lazy loading on one-to-one mapping
Related
I have the following UML structure:
I'm trying to map it similar to this:
<class name="Parent" table="ParentTable">
<id name="Id">
<generator class="guid.comb" />
</id>
<one-to-one name="Child" class="IChild" property-ref="Parent" cascade="all" />
</class>
<class name="IChild" table="ChildTable" abstract="true">
<id name="Id">
<generator class="foreign">
<param name="property">Parent</param>
</generator>
</id>
<discriminator column="TypeKey" type="String"/>
<one-to-one name="Parent" class="Parent" />
<one-to-one name="Child" class="IGrandchild" property-ref="Parent" cascade="all" />
</class>
<subclass name="ConcreteChild" extends="IChild" discriminator-value="ConcreteChild1">
<property name="SomeProperty"/>
</subclass>
<class name="IGrandchild" table="GrandchildTable" abstract="true">
<id name="Id">
<generator class="guid.comb" />
</id>
<discriminator column="TypeKey" type="String"/>
<many-to-one name="Parent" class="IChild" unique="true" column="ChildTableFk" />
</class>
<subclass name="ConcreteGrandchild" extends="IGrandchild" discriminator-value="ConcreteGrandchild1">
<property name="SomeOtherProperty"/>
</subclass>
Working against SQL this doesn't work (strangely, with SQLite this does work). NHibernate first inserts the Parent with the generated guid. It then inserts the child with the same guid. But when it comes to inserting the grandchild, it inserts it with ChildTableFk null (and never attempts to update the FK value).
Additional points:
I prefer not changing the IChild mapping to use many-to-one with FK if possible (I prefer a shared PK).
I can't change the IGrandChild mapping to use a foreign generator because the grandchild can be changed after the object graph is changed, which NHibernate does not support with a foreign generator (an IChild instance, on the other hand, will never change for the lifecycle of a given IParent).
Other than that, any suggestions are welcome, including alternate mapping styles (as long as they support polymorphic IChild and IGrandchild objects).
Oops, seems that I just forgot to set the Parent property on the Grandchild. Should have been the first thing I looked at.
My question is similar to this question.
But I want to query by the discriminator of a child entity associated with a one-to-one relationship, and without knowing the exact discriminator value, i.e., by type not by string.
Given an hbm like:
<class name="Parent" table="ParentTable">
<id name="Id">
<generator class="guid.comb" />
</id>
<one-to-one name="Child" class="IChild" property-ref="Parent" cascade="all" />
</class>
<class name="IChild" table="ChildTable" abstract="true">
<id name="Id">
<generator class="foreign">
<param name="property">Parent</param>
</generator>
</id>
<discriminator column="TypeKey" type="String"/>
<one-to-one name="Parent" class="Parent" />
</class>
<subclass name="ConcreteChild" extends="IChild" discriminator-value="Concrete1">
<property name="SomeProperty"/>
</subclass>
Or any other one-to-one configuration, I would like to run a query similar to this:
public IEnumerable<Parent> FindByChild(Type childType)
{
return session.CreateCriteria<Parent>()
.Add(Restrictions.Eq("Child.class", childType))
.List<Parent>();
}
Further information:
The above criteria query fails because "Child.class" is not recognized as valid.
A similar query using HQL fails because NHibernate uses the fullname of childType rather than its discriminator value in the query.
Have you tried using an alias? I can't test it right now on my machine, but should be similar to this..
return session.CreateCriteria<Parent>()
.CreateAlias("ParentChild","Child")
.Add(Restrictions.Eq("ParentChild.class", childType))
.List<Parent>();
where ParentChild is just the name I used to refer to the Child entity of the Parent class
I have two classes: Family and Address.
A family has a physical address and a mailing address.
The mapping file for Family looks like:
....
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<many-to-one name="PhysicalAddress" class="Address" column="PhysicalAddressId" cascade="all" unique="true" />
<many-to-one name="MailingAddress" class="Address" column="MailingAddressId" cascade="all" unique="true" />
...
The mapping file for Address looks like:
...
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="StreetAddress1" column="StreetAddress1" />
<property name="StreetAddress2" column="StreetAddress2"/>
<property name="City" column="City" />
<property name="State" column="State" />
<property name="ZipCode" column="ZipCode" />
...
(Note that Family-PhysicalAddress and Family-MailingAddress are one-to-one relationships.)
What I would like to happen is that when I execute
aFamily.MailingAddress = null;
session.Save(aFamily);
session.Flush();
I expect NHibernate to automatically delete the mailing address record from SQL Server for me.
BUT, that doesn't happen. NHibernate does not delete the address record from SQL Server.
Is there any way I can make it work?
Thank you!
This behaviour isn't supported by NHibernate. Of course the problem is that you probably don't have access to the NHibernate session in your domain logic where the change is made.
One possible -- though admittedly not ideal solution -- is to simply run another process to clean up orphaned entities.
Here is a discussion of this scenario:
http://colinjack.blogspot.com/2008/03/nhibernate-gotchas-orphans-and-one-to.html
And a link to a ticket on the issue:
https://nhibernate.jira.com/browse/NH-1262
Unfortunately NHibernate currently does not support automatic deletions of orhphans for many-to-one (Hibernate v3 in Java does support it). It is only supported on lists (cascade="all-delete-orphan").
What you can try to do is to use component mapping. Maybe it is possible to embed many-to-one into a component.
But I think it would better to explicitly delete the related object.
Currently I have the following classes:
class Article with properties id, title and body
class Question : Article with an extra PostedBy property
Then I have a table called Article with the above properties and a table called questions with an ID a foreign key articleID and a PostedBy. Both are in different schemas
I would like to know how are my mappings going to look to represent this relation. Both classes are in different assemblies and i would be very reluctant to put Question logic in Article class/mapping and its assembly.
NHibernate supports three basic inheritance strategies.
table per class hierarchy
table per subclass
table per concrete class
It sounds like you are looking for the table per subclass strategy as you have a table for your Article class and another table for the extra properties on the Question subclass. The mapping might looks something like this:
<class name="Article" table="Article">
<id name="Id" type="Int64" column="ArticleId">
<generator class="native"/>
</id>
<property name="Title" column="Title"/>
<property name="Body" column="Body"/>
...
<joined-subclass name="Question" table="Question">
<key column="ArticleId"/>
<property name="PostedBy" column="PostedBy"/>
...
</joined-subclass>
</class>
However, this doesn't meet your desire to keep the mappings entirely separate. You could have entirely separate mappings, but this might have some side effects as allowing Question to be loaded as a plain Article instead of a Question. With separate mapping the Article class would be straight-forward as expected. The Question class would include a join to access the properties stored in the Article table.
<class name="Article" table="Article">
<id name="Id" type="Int64" column="ArticleId">
<generator class="native"/>
</id>
<property name="Title" column="Title"/>
<property name="Body" column="Body"/>
...
</class>
<class name="Question" table="Question">
<id name="Id" type="Int64" column="QuestionId">
<generator class="native"/>
</id>
<property name="PostedBy" column="PostedBy"/>
...
<join table="Article">
<key column="ArticleId"/>
<property name="Title" column="Title"/>
<property name="Body" column="Body"/>
</join>
</class>
Ok, new to nhibernate and I am working on a project that has already fully implemented it.
Scenerio: One class (Person) has two joined subclasses (RoleA and RoleB).
What I need is that a given person can actually be both in RoleA and RoleB. How, when given a person that is already created and in RoleA, can I then make them also in RoleB while maintaining the relationships with RoleA?
So, you have something like the following (with Students and Teachers taking the place of RoleA and RoleB):
<class name="Person" table="Persons" >
<id name="Id" column="PersonID">
<generator class="native" />
</id>
<property name="Name" column="Name" not-null="true" />
<joined-subclass name="Student" table="Students">
<key column="PersonID" />
<property name="Grade" column="Grade" not-null="true" />
</joined-subclass>
<joined-subclass name="Teacher" table="Teachers">
<key column="PersonID" />
<property name="ClassName" column="ClassName" not-null="true" />
</joined-subclass>
</class>
If that is the case, your best bet is to use a one-to-one mapping to accomplish the same thing. Here is a good reference: http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-onetoone
This person had a similar problem as you, and ended up going with the one-to-one mapping option:
http://groups.google.com/group/nhusers/browse_thread/thread/1d83e0cd3c2bf58f