I am trying to map a legacy bidirectional one-to-one with shared PK using 2
bags. One end of the relation can be null.
The reason i am doing this is for performance consideration (mostly to
provide lazy-loading). I have tried doing this with many-to-one but i get
all kind of strange issues plus i always need to check for an invalid proxy
due to the possibility that there is no associated record in one end of the
relation.
Here are the tables:
[image: enter image description here]
TableB association can be null. If TableB association exits, TableA
association must exists.
Here is my mapping+code:
Base:
public abstract class Base
{
public virtual Guid ID { get; set; }
public virtual string getObjectID()
{
return this.ID.ToString();
}
}
TableA+mapping:
TableA.cs
public class TableA : Base
{
public virtual string Name { get; set; }
protected virtual IList<TableB> _tableBList { get; set; }
public virtual TableB TableB
{
get
{
TableB retValue = null;
if (_tableBList != null && _tableBList.Count > 0)
retValue = _tableBList[0];
return retValue;
}
set
{
if (_tableBList == null)
{
_tableBList = new List<TableB>();
}
if (value == null)
{
_tableBList.Clear();
return;
}
if (_tableBList.Count == 0)
{
_tableBList.Add(value);
}
else
{
_tableBList[0] = value;
}
}
}
}
TableA.hbm.xml
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NHibernateTest" assembly="NHibernateTest">
<class name="TableA" table="TableA" >
<id name="ID" type="guid">
<column name="ID" />
<generator class="guid.comb" />
</id>
<bag name="_tableBList" cascade="all-delete-orphan" lazy="true">
<key column="ID" />
<one-to-many class="TableB" />
</bag>
<property name="Name" />
</class>
</hibernate-mapping>
TableB
public class TableB:Base
{
public virtual string ChildName { get; set; }
protected virtual IList<TableA> _tableAList { get; set; }
public virtual TableA TableA
{
get
{
TableA retValue = null;
if (_tableAList != null && _tableAList.Count > 0)
retValue = _tableAList[0];
return retValue;
}
set
{
if (_tableAList == null)
{
_tableAList = new List<TableA>();
}
if (_tableAList.Count == 0)
{
_tableAList.Add(value);
}
else
{
_tableAList[0] = value;
}
}
}
}
TableB.hbm.xml
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NHibernateTest" assembly="NHibernateTest">
<class name="TableB" table="TableB" >
<id name="ID" type="guid">
<column name="ID" />
<generator class="NHibernateTest.PropertyAccessGenerator,
NHibernateTest">
<param name="property-name">TableA</param>
</generator>
</id>
<bag name="_tableAList" lazy="true">
<key column="ID" foreign-key="ID"/>
<one-to-many class="TableA"/>
</bag>
<property name="ChildName" />
</class>
</hibernate-mapping>
NHibernateTest.PropertyAccessGenerator, NHibernateTest
public class PropertyAccessGenerator : IIdentifierGenerator,IConfigurable
{
private string propertyName;
private string entityName;
public object Generate(ISessionImplementor sessionImplementor,
object obj)
{
ISession session = (ISession)sessionImplementor;
var persister =
sessionImplementor.Factory.GetEntityPersister(entityName);
object associatedObject =
ReflectionUtil.ReflectionHelper.CallPropertyGetter(obj, propertyName);
if (associatedObject == null)
{
throw new IdentifierGenerationException("attempted to
assign id from null one-to-one property: " + propertyName);
}
object id =
ReflectionUtil.ReflectionHelper.CallPropertyGetter(associatedObject, "ID");
if (session.Contains(obj))
{
//abort the save (the object is already saved by a circular
cascade)
return IdentifierGeneratorFactory.ShortCircuitIndicator;
}
return id;
}
public void Configure(NHibernate.Type.IType type,
IDictionary<string, string> parms, NHibernate.Dialect.Dialect dialect)
{
parms.TryGetValue(IdGeneratorParmsNames.EntityName, out
entityName);
parms.TryGetValue("property-name", out propertyName);
if (string.IsNullOrEmpty(propertyName))
{
throw new MappingException("param named \"property-name\"
is required for property access generation strategy");
}
}
}
With the above mapping and code i can Insert/Update but is failling when i
am trying to delete tableB association.
What i am doing wrong? Did someone implemented something similar?
Sample code:
class Program
{
static void Main(string[] args)
{
Configuration configuration = new Configuration();
configuration.Configure();
ISessionFactory factory = configuration.BuildSessionFactory();
using (var session = factory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
////this works
//TableA tableA =
session.Load<TableA>(Guid.Parse("48B0DBDB-CBB6-4C9E-AC96-A1BA00E11847"));
//tableA.Name = "test";
//session.Save(tableA);
//tx.Commit();
//this works
//TableA tableA =
session.Load<TableA>(Guid.Parse("48B0DBDB-CBB6-4C9E-AC96-A1BA00E11847"));
//tableA.TableB = new TableB() { ChildName = "asdasd" };
//session.Save(tableA);
//tx.Commit();
//this fails
TableA tableA =
session.Load<TableA>(Guid.Parse("48B0DBDB-CBB6-4C9E-AC96-A1BA00E11847"));
tableA.TableB = null;
session.Save(tableA);
tx.Commit();
}
}
Console.ReadLine();
}
}
Thanks
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/nhusers?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.