Logo

NHibernate

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 :)...

 

 

G'day,

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:

 
Documents
-------------------
(PK) Id
(FK Unique) DocumentFileId
Name

DocumentFiles
-------------------
(PK) Id
Data


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" />
    </id>
    <property name="Name" column="Name" type="string" />
    <many-to-one name="DocumentFile" cascade="all-delete-orphan"
                 lazy="proxy" column="DocumentFileId" unique="true" />

  </class>
</hibernate-mapping>

<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" />
    </id>   

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



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.

 

 

Thanks
Stefan

© NHibernate Community 2024