Reputation: 47199
I have used nHibernate in my latest project and successfully mapped all the basic relationships where the values existed in either the primary table I was working with or through a simple relationship like a composite.
Where I am getting stuck is how does one go about mapping complex joins?
For example I have an entity called Contact
each contact
has your usual properties like Name, DOB, Phone.... But I also need it to have a property called AccreditationList
which would be a List<Accreditation>
.
Here is a sample of the Contact XML declaration.
<class name="Contact" table="Contact" lazy="true">
<id name="ID" column="ContactID" type="guid">
<generator class="guid" />
</id>
<property name="FirstName">
<column name="FirstName" sql-type="nvarchar(500)" not-null="true" />
</property>
<property name="LastName">
<column name="LastName" sql-type="nvarchar(500)" not-null="true" />
</property>
<bag name="AccreditationList" lazy="true">
//How do I express the relationship here?
</bag>
</class>
The List<Accreditation>
can only be determined through a series of joins like this.
SELECT Accreditation.* FROM CourseEnrolment
INNER JOIN Course ON Course.CourseID = CourseEnrolment.CourseID
INNER JOIN CourseType ON CourseType.CourseTypeID = Course.CourseTypeID
INNER JOIN Accreditation ON Accreditation.AccreditationID = CourseType.AccreditationID
WHERE CourseEnrolment.ContactID = :ContactID
Is the only way to accomplish this by manually invoking the SQL through nHibernate in code with CreateSQLQuery
or can I express this relationship using something like named queries? What is the correct approach? Any guidance would be appreciated.
Upvotes: 1
Views: 419
Reputation: 6752
I see a couple of options:
You can use SqlSelect
, SqlUpdate
etc.. to specify an arbitrary SQL statement for selecting / updating etc.. (a mapping-by-code example; I'm sure there's an XML equivalent)
You could map your SQL query to a QueryOver
query, and use it to initialize your Accreditation
collection. Something along the lines of:
public Contact GetContact(int id)
{
var contact = _session.Get(id);
contact.AccreditationList = _session.QueryOver<Accreditation>() /* your query here */;
return contact;
}
However!! this method has several drawbacks-
GetContact
method, your collection won't be populated correctly. You could map the intermediate entity (Course
) to your Contact
entity (you can have it as a private member, if you don't want to expose them), and then your AccreditationList
property would be
public IEnumerable<Accreditaion> AccreditationList
{
get
{
return _courses.SelectMany(course => course.Accreditations);
}
}
You wouldn't be able to manipulate the Contact
's AccreditationList
directly, though.
The best solution would be to have something like QueryOverSelect
option in the mapping, but AFAIK there isn't...
Personally I'd go with the 3rd option, since it seems the cleanest to me.
Upvotes: 1