many-to-many mapping in NHibernate - nhibernate

I'm looking to create a many to many relationship using NHibernate. I'm not sure how to map these in the XML files. I have not created the classes yet, but they will just be basic POCOs.
Tables
Person
personId
name
Competency
competencyId
title
Person_x_Competency
personId
competencyId
Would I essentially create a List in each POCO for the other class? Then map those somehow using the NHibernate configuration files?

You can put the many-to-many relation to either class, or even to both. This is up to your domain model. If you map it to both, one of them is inverse.
class Person
{
// id ...
IList<Competency> Competencies { get; private set; }
// you domain model is responsible to manage bidirectional dependencies.
// of course this is not a complete implementation
public void AddCompetency(Competency competency)
{
Competencies.Add(competency);
competency.AddPerson(this);
}
}
class Competency
{
// id ...
IList<Person> Persons { get; private set; }
}
Mapping:
<class name="Person">
<id ....>
<bag name="Competencies" table="Person_x_Competency">
<key column="personId"/>
<many-to-many class="Competency" column="competencyId"/>
</bag>
</class>
<class name="Competency">
<id ....>
<bag name="Persons" table="Person_x_Competency" inverse="true">
<key column="competencyId"/>
<many-to-many class="Person" column="personId"/>
</bag>
</class>
Only make it bidirectional if you really need it.
By the way: it is much better to write the classes first and create the database design afterwards. The database can be exported from the mapping files. This is very useful.

Related

Mapping a Reflexive Many-to-Many relationship with NHibernate?

I am trying to use NHibernate with an existing database. The database records unidirectional relationships between users:
Users
UserId PK
Name
Relationships
RelationshipId PK
ParentId FK:Users_UserId
ChildId FK:Users_UserId
I want to represent this using NHibernate. At the moment, I have the following POCO object:
class User {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public ICollection<User> ParentUsers {get; set;}
public ICollection<User> ChildUsers {get; set;}
}
I also have this mapping file:
<class name="User" table="Users">
<id name="Id"></id>
<property name="Name"></property>
</class>
I've looked at guides on the web, but I can't work out what I need to put in the mapping file to wire up my two ICollection properties.
How should I map this data structure? Is my current approach correct, or is it better to create a second POCO class, and just use two many-to-one relationships?
I'm probably missing something, but this should get you started:
<idbag name="ParentUsers" table="Relationships">
<collection-id column="RelationshipId" type="...">
<generator class="..."/>
</collection-id>
<key column="ChildId"/>
<many-to-many column="ParentId" class="User"/>
</idbag>
<idbag name="ChildUsers" table="Relationships">
<collection-id column="RelationshipId" type="...">
<generator class="..."/>
</collection-id>
<key column="ParentId"/>
<many-to-many column="ChildId" class="User"/>
</idbag>
Also, one of the collections should be marked as inverse.

Automatically removing associations when deleting entities in NHibernate

I have the following entities:
namespace NhLists {
public class Lesson {
public virtual int Id { get; set; }
public virtual string Title { get; set; }
}
public class Module {
public virtual int Id { get; set; }
public virtual IList<Lesson> Lessons { get; set; }
public Module() {
Lessons = new List<Lesson>();
}
}
}
And the following mappings:
<class name="Module" table="Modules">
<id name="Id">
<generator class="identity"/>
</id>
<list name="Lessons" table="ModuleToLesson"
cascade="save-update">
<key column="moduleId"/>
<index column="position"/>
<many-to-many
column="lessonId"
class="NhLists.Lesson, NhLists"/>
</list>
</class>
<class name="Lesson" table="Lessons">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Title">
<column name="Title" length="16" not-null="true" />
</property>
</class>
When I delete a lesson by session.Delete(lesson), is there anyway I can have NHibernate automatically update the association in Module.Lessons to remove the entry from the set? Or am I forced to go through all Modules and look for the lesson and remove that by hand?
Edit: Fixed ICollection and <set> in mappings to IList<> and <list> like I want and tested it.
You have false idea. If you want to delete the Lesson object from Module you do that manually. NHibernate just tracks such your action and when session.Commit() is called then the reference between Module and Lesson is deleted in the database.
Calling session.Delete(lesson) deletes the lesson object from database (if foreign keys are set properly then reference between Module and Lesson is deleted of course but it is not responsibility for NHibernate).
In conclusion, it is not possible to delete the lesson object from the Module.Lessons list automatically by calling session.Delete(lesson). NHibernate does not track such entity references.
Turns out that if we do not need IList semantics and can make do with ICollection the update problem can be solved by adding a reference back from Lesson to Module, such as:
public class Lesson {
...
protected virtual ICollection<Module> InModules { get; set; }
...
}
And to the mapping files add:
<class name="Lesson" table="Lessons">
...
<set name="InModules" table="ModuleToLesson">
<key column="lessonId"/>
<many-to-many column="moduleId" class="NhLists.Module, NhLists"/>
</set>
</class>
Then a Lesson deleted is also removed from the collection in Module automatically. This also works for lists but the list index is not properly updated and causes "holes" in the list.

NHibernate Mapping - many-to-one via table

I'm working with an existing database that has the following structure. Changing the database schema is a last resort.
Products
Id
Name
ParentProducts
ParentId
ChildId
I don't want an entity for ParentProducts, I have the following for the children property (still need to test it, but that's the concept).
<bag name="Children" lazy="true" table="dbo.ParentProducts" cascade="save-update" inverse="true" >
<key column="[ChildId]"></key>
<many-to-many column="[ProductId]" class="Product" />
</bag>
What I'm struggling with is how do I create a Parent property? I'd like to do something like the following, but table isn't a valid attribute for many-to-one.
<many-to-one name="Parent" column="[ParentId]" table="dbo.ParentRelated" class="Policy" />
I could create a bag and only ever look at the first item, but that's more of a hack.
Any ideas?
Thanks
Creating a bag is the easiest solution. And you can give it a clean interface:
protected virtual ICollection<Product> Parents { get; set; }
public virtual Product Parent
{
get
{
return Parents.SingleOrDefault();
}
set
{
Parents.Clear();
Parents.Add(value);
}
}
With this, the rest of the code doesn't need to be aware of the DB/mapping structure.

NHibernate: bidirectional many-to-one problem

I have a bidirectional relationship in NHibernate:
<class name="Child" table="Children">
<many-to-one name="Parent" column="ParentId" not-null="true" />
</class>
<class name="Parent">
<set name="Children" lazy="true" table="Children" cascade="all">
<key column="ParentId" not-null="true" />
<one-to-many class="Child" />
</set>
</class>
How do I save it without setting inverse="true" and setting Parent property on Child?
I do not want to do this because it does not make much sense from the POCO perspective.
Alternatively, is it possible to intercept Add called on NHibernate proxy collection (Children)?
In that case, I would just put the Parent setting logic here.
Unless you're willing to make the foreign key nullable and accept an insert followed by an update, that's the way bidirectional one-to-many works in NHibernate.
I do have a generic implementation of this pattern that you can use... it's a proof of concept; it can be useful or not, depending on how you look at it, as it kinda breaks the POCO approach, but... well, here it is:
public interface IHaveParent<T>
{
T Parent { get; set; }
}
public interface IHaveMany<T>
{
ICollection<T> Children { get; }
}
public static class OneToManyHelper
{
public static void AddChild<TParent, TChild>(this TParent parent,
TChild child)
where TChild : IHaveParent<TParent>
where TParent : IHaveMany<TChild>
{
parent.Children.Add(child);
child.Parent = parent;
}
}
With this, you can all AddChild on any parent.
The problem with intercepting Add calls is that you'd always need to instantiate your collections using a special method (which, again, is not POCO).

NHibernate: mapping a dictionary of lists

My class has a field of type Dictionary<string, List<string>>. What's the best way to map it with NHibernate? I'd better leave it as a field, don't want to expose it.
Thanks a lot!
ulu
You can't directly map it. There are two rules to consider:
Always use interfaces for collections (eg. IList<T>, IDictionary<K,V>)
NH does not support nested collections. I've never seen an application for it before
and never heard someone requesting it.
Put your list of string into a class and use interfaces:
class StringList
{
IList<string> Strings { get; private set; }
}
class Entity
{
private IDictionary<string, StringList> stringDict;
}
You might even see some advantages of having such a class.
Mapping:
<class name="Entity">
...
<map name="stringDict" table="Entity_StringDict" access="field">
<key column="Entity_FK"/>
<index column="Key" type="System.String"/>
<composite-element class="StringList">
<bag name="Strings" table="Entity_StringDict_Strings">
<key column="Entity_StringDict_FK"/>
<element type="System.String" column="String"/>
</bag>
</composite-element>
</map>
</class>
Maps to three Tables:
Table Entity
Table Entity_StringDict
Column Entity_FK
Column Key
Table Entity_StringDict_Strings
Column Entity_StringDict_FK
Column String