I'm trying to get NHibernate to use the many side of a collection to manage a bidirectional association to model a zero-to-one relationship.
Parent Class and Map:
public class Parent { private ICollection<Child> children; public Parent() { this.children = new HashedSet<Child>(); } public virtual Guid Id { get; protected internal set; } public virtual Child Child { get { return children.FirstOrDefault(); } set { { this.children.Clear(); if (value != null) { this.children.Add(value); } } } } } public class ParentMap : ClassMap<Parent> { public ParentMap() { this.Id(x => x.Id) .GeneratedBy.GuidComb(); this.HasMany<Child>(Reveal.Member<Parent>("children")) .Access.Field() .Cascade.All() .Not.Inverse() .AsSet(); } } Child Class and Map:
public class Child { public virtual Guid Id { get; protected internal set; } public virtual Parent Parent { get; set; } } public class ChildMap : ClassMap<Child> { public ChildMap() { this.Id(x => x.Id) .GeneratedBy.GuidComb(); this.References(x => x.Parent) .Not.Nullable() .Cascade.All(); } } The following code produces two inserts and an update:
var parent = new Parent(); var child = new Child(); parent.Child = child; child.Parent = parent; session.Save(parent); session.Flush(); Notice the essentially duplicate SQL for the second insert and the following update:
exec sp_executesql N'INSERT INTO [Parent] (Id) VALUES (@p0)',N'@p0 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401' go exec sp_executesql N'INSERT INTO [Child] (Parent_id, Id) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401',@p1='B78C4461-A217-47FC-BE02-9EF30117140A' go exec sp_executesql N'UPDATE [Child] SET Parent_id = @p0 WHERE Id = @p1',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401',@p1='B78C4461-A217-47FC-BE02-9EF30117140A' go While this code produces the infamous not-null property references a null or transient value inverse:
var parent = new Parent(); var child = new Child(); parent.Child = child; //child.Parent = parent; session.Save(parent); session.Flush(); I've found numerous posts about this, but have yet to find a definitive guide on how to do zero-to-one, with inverse=false on the one side.
I've tried the one-to-many/one-to-one method mentioned here.
As well, I've found several open issues on NHibernate about (not)nullable Foreign Keys: NH-941, NH-1050, etc..
What am I doing wrong?
Edit 2011-05-30
So, my temporary solution is to go for the standard inverse=true setting on the many side, and do some magic in the setter of the Parent:
public virtual Child Child { get { return children.FirstOrDefault(); } set { { this.children.Clear(); if (value != null) { value.Parent = this; this.children.Add(value); } } } } But I'm still baffled by the inverse=false behavior, which should be the equivalent of inverse=true on the many-to-one side (interestingly, FluentNhibernate doesn't allow for the ManyToOnePart to set inverse=true like this article recommends).