The object-relational mapper for .NET

How to

This page is converted from the old nhforge.org Wiki. First published by: stefan.sedich on 11-13-2008, Last revision by: John Davidson on 09-07-2011

Lazy Loaded One-To-One With NHibernate

UPDATE 20081114

The one-to-one solution I had posted turned out not to work for updates, :(, in the end I had to use a many-to-one map with a unique foreign key association to get this to work, the updated example is below. Sorry for my EPIC FAIL :)...




I am working on something at the moment and I am storing BLOB data for documents in the database, I am storing things like name and data which is a binary field. |
Now I wan't to load the binary data as loading this all the time is very inneficient. So to get this to work I had to split this to two tables, one with my meta data and another one-to-one
table to store the BLOB. NOW the fun began I created the two tables:

(PK) Id
(FK Unique) DocumentFileId

(PK) Id

From this I created my POCO classes for the Document and DocumentFile map.

public class Document {
    public int Id { get; set; }
    public string Name { get; set; }
    public DocumentFile DocumentFile { get; set; }  

 public class DocumentFile {
    public virtual int Id { get; set; }
    public virtual Document Document { get; set; }
    public virtual byte[] Data { get; set; }   

Now on to the mappings, I thought this would be as easy as created a one-to-one mapping with lazy="proxy" set on the one-to-one on the Document class but this was not the case.
You NEED to set constrained="true" on the mapping, basically going from this post I found: http://www.hibernate.org/162.html#A5. Say we have A->B where this is a 1-1 relationship,
now without a constraint from A-B this means A can exist without B, so there is a possiblity that B is null, a Proxy to B will be not null and won't work here.

But when we know A and B will always belong together it is ok to create a Proxy for B. Now my final mapping files looks like so:


BUUUT  as I soon found out if in the A mapping you constrain B it will mean it will try to insert B first and fail to generate a primary key with the foreign key generator, hence not working as expected, I had to change the mappings to use a many-to-one unique foreign key mapping to get this to work. I updated the mappings below, the main differences are highlighted below:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="NHibernateDocumentTest.Document, NHibernateDocumentTest" table="Documents" lazy="false">
    <id name="Id" column="Id" type="integer">
      <generator class="native" />
    <property name="Name" column="Name" type="string" />
    <many-to-one name="DocumentFile" cascade="all-delete-orphan"
                 lazy="proxy" column="DocumentFileId" unique="true" />


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="NHibernateDocumentTest.DocumentFile, NHibernateDocumentTest" table="DocumentFiles" lazy="true">
    <id name="Id" column="Id" type="integer">
      <generator class="native" />

    <property name="Data" column="Data" type="Byte[]" />
    <one-to-one name="Document" constrained="true" property-ref="DocumentFile" />

And then we are done, this works fine. So the trick is for a one-to-one to work with Lazy loading you must use a unique foreign key associated with a many-to-one mapping to your child.




© NHibernate Community 2024