Reputation: 437
How to create one-to-one relation using NHibernate where other side could be a NULL? For example, I have a Banner entity that has a relation to Image entity like this:
<class name="Banner" table="Banner">
<id name="Id" type="Int64" unsaved-value="0">
<generator class="native" />
</id>
<many-to-one name="Image" unique="true" column="ImageId" not-null="false"/>
<!-- check: In the example this property was without inverse attribute -->
<set name ="BannerSlideSet" fetch="subselect" inverse="true">
<key column="Banner_ID" foreign-key="FK_Banner_BannerSlide" not-null="false" />
<one-to-many class="BannerSlide"/>
</set>
</class>
So, Image can be null for a Banner entity. I create one banner entity with no image without any issues. In DB I have
--------------
ID | ImageId
--------------
1 | NULL
After that, I'm trying to create second Banner instance with no Image as well and get the following error:
NHibernate.Exceptions.GenericADOException: could not insert: [Domain.Entities.Banner][SQL: INSERT INTO Banner (ImageId) VALUES (?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint 'UQ_Banner_7516F70DE6141471'. Cannot insert duplicate key in object 'dbo.Banner'. The duplicate key value is ().
I guess, it happens because I have unique constraint on one-to-many relation between banner and image entities and several Banner instances can't have several NULL values in ImageId field. Question: how I would achieve one-to-nullableone relation with in NHinerbate?
Thanks!
Upvotes: 3
Views: 3537
Reputation: 123861
The solution is to move the ImageId
from the Banner
table. And place it in the Image
table.
This way, whenever we have real (not null) image, we can let:
BannerId
) by Image (many-to-one
from the Image side, and collection one-to-many
of images from the Banner side) or one-to-one
relationship: the ImageId
is the unqiue constrained, generated by the owning Banner's BannerId
.This is the example form the documenation 5.1.11. one-to-one, adjusted to Banner and Image
Now we must ensure that the primary keys of related rows in the BANNER and IMAGE tables are equal. We use a special NHibernate identifier generation strategy called foreign:
The Image mapping:
<class name="Image" table="[Image]">
<id name="Id" column="[ImageId]">
<generator class="foreign">
<param name="property">Banner</param>
</generator>
</id>
...
<one-to-one name="Banner" class="Banner" constrained="true"/>
</class>
The Banner:
<one-to-one name="Image" class="Image"/>
Upvotes: 3