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.


Reply via email to