1
votes

I'm having a problem getting a one-to-one relationship working with fluent nhibernate. I've read a multitude of posts on this and it seems like the preferred approach is the shared primary key method, where the parent and child have the same primary key value and child PK is also FK to parent.

The parent and child classes each have a reference to the other (bi-directional HasOne) and the child is configured to get it's key value from the parent.

I believe I have it setup correctly, but when I create a new Parent, attach a new Child and then try to save it, the parent saves correctly and the key value is updated on the child object, but the child is not actually saved to the DB.

Here are the classes and maps:

public class Parent
{
    public virtual int ParentID { get; set; }
    public virtual string Name { get; set; }

    public virtual Child Child { get; set; }

    public virtual void Add(Child child)
    {
        child.Parent = this;
        Child = child;
    }
}

public class Child
{
    public virtual int ParentID { get; set; }
    public virtual string Name { get; set; }

    public virtual Parent Parent { get; set; }
}

public class ParentMap : ClassMap<Parent>
{
    public ParentMap()
    {
        Id(x => x.ParentID).GeneratedBy.Identity();
        Map(x => x.Name);

        HasOne(x => x.Child).Cascade.All();
    }
}

public class ChildMap : ClassMap<Child>
{
    public ChildMap()
    {
        Id(x => x.ParentID).GeneratedBy.Foreign("Parent");
        Map(x => x.Name);

        HasOne(x => x.Parent).Constrained().ForeignKey();
    }
}

Here is the schema that NHibernate creates (removed some GOs for brevity):

CREATE TABLE [dbo].[Parent](
    [ParentID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](255) NULL,
PRIMARY KEY CLUSTERED 
(
    [ParentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


CREATE TABLE [dbo].[Child](
    [ParentID] [int] NOT NULL,
    [Name] [nvarchar](255) NULL,
PRIMARY KEY CLUSTERED 
(
    [ParentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[Child]  WITH CHECK ADD  CONSTRAINT [FK_ChildToParent] FOREIGN KEY([ParentID])
REFERENCES [dbo].[Parent] ([ParentID])
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_ChildToParent]

So it seems to create the schema I expected. But I just can't get the child to save:

var parent = new Parent() { Name = "Parent_1" };
parent.Add(new Child { Name = "Child_1" });
session.Save(parent);

As mentioned, this will save the parent correctly and update the ParentID property on the Child object with the value from the parent, but the Child is not actually saved to the DB and no error is generated.

Any idea what I'm doing wrong?

1

1 Answers

1
votes

Never mind. I feel stupid. The mappings are correct, but you have to wrap the Save in a transaction for the child object to be persisted, which I wasn't doing in my test app. Once I added the transaction it worked as expected.