Hi all
I want to use a ternary assocation in combination with nhibernate. That means, i have three domain objects and four tables (one table per entity and one for the association).
I've read the user manual and several forum posts but i've found nowhere a detailed explanation about using and mapping ternary association in nhibernate.
The user manual only contains the following section:
--------------------------------------------------------------------------------
6.9. Ternary Associations
There are two possible approaches to mapping a ternary association. One approach is to use composite elements (discussed below). Another is to use a Map with an association as its index:
<map name="contracts" lazy="true">
<key column="employer_id"/>
<index-many-to-many column="employee_id" class="Employee"/>
<one-to-many column="contract_id" class="Contract"/>
</map>
<map name="connections" lazy="true">
<key column="node1_id"/>
<index-many-to-many column="node2_id" class="Node"/>
<many-to-many column="connection_id" class="Connection"/>
</map>
--------------------------------------------------------------------------------
With this few lines it's not completely clear how to work with a ternary association. For example how does the mapping know in which table to store the assocations?
In my case i've 3 entities:
Employee
BusinessLine
Right
In Employee i want to store a set of Right's which belongs to a specific BusinessLine. In the code i've the following:
Code:
....
private IDictionary m_businessLineRights;
public Employee() {
m_businessLineRights = new Hashtable();
}
public void AddRight(BusinessLine businessLine, Right right) {
if (!m_businessLineRights.Contains(businessLine)) {
m_businessLineRights.Add(businessLine, new HashedSet());
}
((ISet)m_businessLineRights[businessLine]).Add(right);
}
public ISet GetRightsByBusinessLine(BusinessLine businessLine) {
if(m_businessLineRights.Contains(businessLine)){
return ((ISet) m_businessLineRights[businessLine]);
}
return null;
}
...
The mapping file looks like this:
...
<map name="BusinessLineRights" lazy="false">
<key column="EmployeeId"/>
<index-many-to-many
column="BusinessLineId"
class="Authorization.BusinessLine"/>
<many-to-many
column="RightId"
class="Authorization.Right"/>
</map>
...
--> For me it's not clear where to specify the assocation table. In my case it's called BusinessLineEmployeeRight and contains 3 foreign keys (EmployeeId, RightId, BusinessLineId)
The problem occurs in the flushing process:
...
Code:
BusinessLine businessLine = new BusinessLine("BL1");
Right right1 = new Right("Right1");
Right right2 = new Right("Right2);
employee.AddRight(businessLine, right1);
employee.AddRight(businessLine, right2);
session.Save(businessLine);
session.Save(right1);
session.Save(right2);
session.Save(employee);
session.Flush();
...
When i stepped through the nhibernate code with the debugger, i found out that the exception occurs in the class "NHibernate.Impl.Printer" in the method "ToString".
The whole exception stack trace looks like this:
at NHibernate.Property.BasicGetter.Get(Object target) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Property\BasicGetter.cs:line 45
at NHibernate.Persister.AbstractEntityPersister.GetIdentifier(Object obj) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Persister\AbstractEntityPersister.cs:line 304
at NHibernate.Proxy.NHibernateProxyHelper.GetIdentifier(Object obj, IClassPersister persister) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Proxy\NHibernateProxyHelper.cs:line 90
at NHibernate.Type.EntityType.ToString(Object value, ISessionFactoryImplementor factory) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Type\EntityType.cs:line 86
at NHibernate.Type.PersistentCollectionType.ToString(Object value, ISessionFactoryImplementor factory) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Type\PersistentCollectionType.cs:line 83
at NHibernate.Impl.Printer.ToString(Object entity) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Impl\Printer.cs:line 45
at NHibernate.Impl.Printer.ToString(IEnumerator enumerator) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Impl\Printer.cs:line 94
at NHibernate.Impl.SessionImpl.FlushEverything() in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Impl\SessionImpl.cs:line 2890
at NHibernate.Impl.SessionImpl.Flush() in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Impl\SessionImpl.cs:line 2843
at EL4Net.Transaction.NHibernate.NHTransactionScope.PreCompleteTransaction() in e:\VS_PROJECTS\ELCA\EL4NET\Public\2-Framework\EL4Net.Data.NHibernate\NHibernateTransactionScope.cs:line 90
at EL4Net.Transaction.LightweightTransactionScope.Complete() in e:\VS_PROJECTS\ELCA\EL4NET\Public\2-Framework\EL4Net.Data\Transaction\LightweightTransactionScope.cs:line 567
at TenderTracker.AuthorizationDataAccess.Save(Employee employee) in E:\VS_PROJECTS\ELCA\TenderTracker\TenderTracker.DataAccess\AuthorizationDataAccess.cs:line 99
at TenderTracker.AuthorizationDataAccessTest.TestSaveAndLoadEmployeeBusinessLineAndRight() in E:\VS_PROJECTS\ELCA\TenderTracker\TenderTracker.DataAccess.Tests\AuthorizationDataAccessTest.cs:line 109
--TargetException
at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
at NHibernate.Property.BasicGetter.Get(Object target) in e:\VS_PROJECTS\ELCA\EL4NET\Public\1-Utilities\NHibernate\Property\BasicGetter.cs:line 41
Could anyony help me with these issues? Thanks in advance.