I have just added not-null="true" to all of my many-to-one relations.
My schema contains two closed loops.
I now get a PropertyValueException stating that "not-null property references a null or transient value".
You'll have to excuse my lack of creativity here, but the following minimal example should replicate the problem.
Two and Three both reference One. Four references Two and Three.
Code:
using System;
using Iesi.Collections;
class One {
private Guid _ID;
private ISet _Twos;
private ISet _Threes;
public Guid ID {
get { return _ID; }
set { _ID = value; }
}
public One() {
_Twos = new HashedSet();
_Threes = new HashedSet();
}
public ISet Twos {
get { return _Twos; }
set { _Twos = value; }
}
public ISet Threes {
get { return _Threes; }
set { _Threes = value; }
}
}
class Two {
private Guid _ID;
private One _One;
private ISet _Fours;
public Guid ID {
get { return _ID; }
set { _ID = value; }
}
public Two() {
_Fours = new HashedSet();
}
public One One {
get { return _One; }
set { _One = value; }
}
public ISet Fours {
get { return _Fours; }
set { _Fours = value; }
}
}
class Three {
private Guid _ID;
private One _One;
private ISet _Fours;
public Guid ID {
get { return _ID; }
set { _ID = value; }
}
public Three() {
_Fours = new HashedSet();
}
public One One {
get { return _One; }
set { _One = value; }
}
public ISet Fours {
get { return _Fours; }
set { _Fours = value; }
}
}
class Four {
private Guid _ID;
private Two _Two;
private Three _Three;
public Guid ID {
get { return _ID; }
set { _ID = value; }
}
public Two Two {
get { return _Two; }
set { _Two = value; }
}
public Three Three {
get { return _Three; }
set { _Three = value; }
}
}
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.0"
assembly="Test"
>
<class
name="One"
dynamic-update="true"
>
<id name="ID">
<generator class="NHibernate.Id.GuidCombGenerator, NHibernate" />
</id>
<set name="Twos" inverse="true" cascade="all" lazy="true" >
<key column="OneID" />
<one-to-many class="Two" />
</set>
<set name="Threes" inverse="true" cascade="all" lazy="true" >
<key column="OneID" />
<one-to-many class="Three" />
</set>
</class>
<class
name="Two"
dynamic-update="true"
>
<id name="ID">
<generator class="NHibernate.Id.GuidCombGenerator, NHibernate" />
</id>
<many-to-one name="One" column="OneID" not-null="true" />
<set name="Fours" inverse="true" cascade="all" lazy="true" >
<key column="TwoID" />
<one-to-many class="Four" />
</set>
</class>
<class
name="Three"
dynamic-update="true"
>
<id name="ID">
<generator class="NHibernate.Id.GuidCombGenerator, NHibernate" />
</id>
<many-to-one name="One" column="OneID" not-null="true" />
<set name="Fours" inverse="true" cascade="all" lazy="true" >
<key column="ThreeID" />
<one-to-many class="Four" />
</set>
</class>
<class
name="Four"
dynamic-update="true"
>
<id name="ID">
<generator class="NHibernate.Id.GuidCombGenerator, NHibernate" />
</id>
<many-to-one name="Two" column="TwoID" not-null="true" />
<many-to-one name="Three" column="ThreeID" not-null="true" />
</class>
</hibernate-mapping>
Code:
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
static class Program {
static void Main() {
Configuration config = new Configuration();
config.Properties.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
config.Properties.Add("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect");
config.Properties.Add("hibernate.connection.driver_class", "NHibernate.Driver.SqlClientDriver");
config.Properties.Add("hibernate.connection.connection_string",
"Data Source=(local);Integrated Security=SSPI;Initial Catalog=test2");
config.AddAssembly("Test");
new SchemaExport(config).Create(true, true);
using (ISession session = config.BuildSessionFactory().OpenSession())
using (ITransaction transaction = session.BeginTransaction()) {
for (int i = 0; i < 3; i++) {
One o = new One();
for (int j = 0; j < 3; j++) {
Two tw = new Two();
Three th = new Three();
for (int k = 0; k < 3; k++) {
Four f = new Four();
tw.Fours.Add(f);
th.Fours.Add(f);
f.Two = tw;
f.Three = th;
}
o.Twos.Add(tw);
o.Threes.Add(th);
tw.One = o;
th.One = o;
}
session.Save(o);
}
transaction.Commit();
}
}
}
Any advice would be great.
Nathan