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