Hi All,
I am new to NHibernate (the last ORM I used in anger was Rails' ActiveRecord) and am having a devil of a time persisting collections.
This test works:
Code:
[Test]
public void NHibernateService_UpdateA_SavesAWithSingleC()
{
ClassA a = service.GetA(existingId);
ClassC c = a.BArray[0].C;
var newA = new ClassA
{
BArray = new[]
{
new ClassB { C = c }
}
};
service.UpdateA(newA);
}
... whereas this test does not:
Code:
[Test]
public void NHibernateService_UpdateA_SavesAWithIdenticalC()
{
ClassA a = service.GetA(existingId);
ClassC c = a.BArray[0].C;
var newA = new ClassA
{
BArray = new[]
{
new ClassB { C = c },
new ClassB { C = c },
}
};
service.UpdateA(newA);
}
It fails with the following exception:
Code:
NHibernate.NonUniqueObjectException was unhandled by user code
Message="a different object with the same identifier value was already associated with the session: 162, of class: NHibernateService.ClassC
The mappings are as follows:
Code:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateService.ClassA, NHibernateService" lazy="false" table="CLASS_A">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<bag name="BArray" cascade="all" inverse="false">
<key column="A_ID" />
<one-to-many class="NHibernateService.ClassB, NHibernateService" />
</bag>
</class>
<class name="NHibernateService.ClassB, NHibernateService" lazy="false" table="CLASS_B">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<many-to-one name="C" class="NHibernateService.ClassC, NHibernateService" column="C_ID" not-null="true" cascade="all" lazy="false" />
<many-to-one name="Parent" class="NHibernateService.ClassA, NHibernateService" column="A_ID" not-null="true" cascade="all" lazy="false" />
</class>
<class name="NHibernateService.ClassC, NHibernateService" lazy="false" table="CLASS_C">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
</class>
</hibernate-mapping>
And the object files are simple too:
Code:
[DataContract]
[Serializable]
public class ClassA
{
[DataMember]
public int Id { get; set; }
[DataMember]
public IList<ClassB> BArray { get; set; }
[OnDeserialized]
private void GenerateBacklinks(StreamingContext context)
{
if (BArray != null)
{
foreach (ClassB b in BArray)
{
b.Parent = this;
}
}
}
}
[DataContract]
[Serializable]
public class ClassB
{
[DataMember]
public int Id { get; set; }
[DataMember]
public ClassC C { get; set; }
public ClassA Parent { get; set; }
}
[DataContract]
[Serializable]
public class ClassC
{
[DataMember]
public int Id { get; set; }
}
Finally, the simple method on the WCF service that does the persistence:
Code:
public int UpdateA(ClassA target)
{
using (ISession session = GetSession())
{
session.SaveOrUpdate(target);
session.Flush();
session.Close();
}
return target.Id;
}
Can anyone give me any pointers as to where I might be going wrong? I don't think that what I'm doing is so demanding, and this suggests I'm missing something pretty simple ...