This is a problem of unidirectional one-to-one mapping in NHibernate.
public class Student
{
public int ID { get; set; }
public int Roll { get; set; }
public int RegNo { get; set; }
public string Name { get; set; }
public StudentDetail StudentDetail { get; set; }
}
public class StudentDetail
{
public int ID { get; set; }
public string Father { get; set; }
public string Mother { get; set; }
}
How can I map these classes (how do the hbm mapping files look like) to the following case of one-to-one relationship?
Please have a look at the classes and the table very carefully.
Where can I put the <many-to-one>
tag in Student.hbm.xml
or StudentDetail.hbm.xml
? If I put it in Student.hbm.xml
, how can I map the column StudentDetail.StudentID
, coz it is in a different table?
So this mapping:
<class name="Student" table="Student">
<id name="ID" column="ID">
<generator class="native"/>
</id>
.......
<many-to-one class="StudentDetail" name="StudentDetail" column="StudentID" unique="true" cascade="all" />
</class>
generates the following exception:
{"Invalid column name 'StudentID'."}
On the other hand <many-to-one>
can't be placed in StudentDetail.hbm.xml
. Coz, StudentDetail.cs
doesn't contain any property of type Student
.
Can I use <one-to-one>
-tag? If yes where should I place it, in Student.cs
or StudentDetail.cs
? And how should I configure it?
Case #1:
In Student...
<one-to-one name="StudentDetail"
cascade="save-update,delete"
property-ref="Student" />
In StudentDetail...
<many-to-one name="Student"
column="StudentID"
unique="true"
cascade="none" />
Note that you'll have to have a property in your StudentDetail class that refers to a Student oobject (called Student). Also, your cascades might be different depending on your usage. You most likely want the delete cascade in there, though.
The unique="true"
ensures the one-to-one mapping on the StudentDetail side.
Case #2:
Just exchange the two mappings, making sure you change the property names to the opposite class.
Look here for more info: http://nhforge.org/blogs/nhibernate/archive/2009/04/19/nhibernate-mapping-lt-one-to-one-gt.aspx
You can map it as a one-to-many, with the collection property hidden and only its first element publicly exposed:
public class Student
{
public virtual int ID { get; set; }
public virtual int Roll { get; set; }
public virtual int RegNo { get; set; }
public virtual string Name { get; set; }
protected virtual IList<StudentDetail> StudentDetails { get; set; }
public virtual StudentDetail StudentDetail
{
get
{
if (StudentDetails.Count == 0) return null;
return StudentDetails[0];
}
set
{
if (StudentDetails.Count != 0) throw new Exception();
StudentDetails.Add(value);
value.Student = this;
}
}
}
You could handle the setter better than this - the point is to make sure you don't add multiple rows to the one-to-many. Obviously in this, StudentDetails
is mapped but StudentDetail
isn't in your .hbm.xml or Fluent mappings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With