7

I have a child table containing an id to the parent. This is a one to one mapping, but the child table might be missing values. I'm having problems mapping this without getting an error though... I've tried several things; mapping the same column, having distinct properties etc..

Parent table
  int id

Child table
  int parentid

Parent class
  int id

Child class
  Parent parent // note I'm referencing parent, not using an int id..

Mapping

Id(x => x.Parent)
  .Column("parentid"); // fails

Id(x => x.Parent.Id)
  .Column("parentid"); // fails

References(x => x.Parent)
  .Column("parentid"); // fails - missing id

// Adding an id field in addition to parent for
// child class (id is then the same as parent.id)
// fails on save
Id( x => x.Id ) 
  .Column("parentid");
References(x => x.Parent)
  .Column("parentid");

I would like the child class not to have a distinct Id field, but rather only a reference to parent as there can never be a child without a parent. In the database however, I want to just store the parent's id.

Any ideas how I might do this?

ahsteele
  • 26,243
  • 28
  • 134
  • 248
simendsjo
  • 4,739
  • 2
  • 25
  • 53

3 Answers3

5

The following works:

Id(x => x.Parent.Id).Column("MemberID");
References(x => x.Parent).Column("MemberID").ReadOnly();

The ReadOnly for the reference is important to not get an exception

EDIT: Wasn't so simple...

My child class still had the Id property being called. Seems the Id reference for Parent.Id confuses nhibernate, and it tries to call child.Id instead. I added the following to child, and now it seems to work.. A pretty ugly hack though.

public virtual int Id {
    get { return Parent.Id; }
    set { Debug.Assert(value == Parent.Id); }
}
simendsjo
  • 4,739
  • 2
  • 25
  • 53
0

FluentNHibernate's API has changed over the years so I'm not sure if this syntax was available when this question was originally asked but you can now use a reference as an id if you map it as a composite id. I wouldn't call this a hack but it is a little strange that you have to map the reference to the parent entity as part of a composite id. Here's a full example:

public class ParentMap : ClassMap<Parent>
{
    public ParentMap()
    {
        Table( "StackOverflowExamples.dbo.Parent" );

        Id( x => x.ParentId );
        Map( x => x.FirstName );
        Map( x => x.LastName );
    }
}

public class OnlyChildOfParentMap : ClassMap<OnlyChildOfParent>
{
    public OnlyChildOfParentMap()
    {
        Table( "StackOverflowExamples.dbo.OnlyChildOfParent" );

        CompositeId().KeyReference( x => x.Parent, "ParentId" );
        Map( x => x.SomeStuff );
        Map( x => x.SomeOtherStuff );
    }
}

public class Parent
{
    public virtual int ParentId { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}

public class OnlyChildOfParent
{
    public virtual Parent Parent { get; set; }
    public virtual string SomeStuff { get; set; }
    public virtual string SomeOtherStuff { get; set; }

    #region Overrides

    public override bool Equals( object obj )
    {
        if ( obj == null || GetType() != obj.GetType() )
            return false;

        var child = obj as OnlyChildOfParent;

        if ( child != null && child.Parent != null )
        {
            return child.Parent.ParentId == Parent.ParentId;
        }

        return false;
    }

    public override int GetHashCode()
    {
        return Parent.ParentId;
    }

    #endregion Overrides
}
Randy Burden
  • 2,611
  • 1
  • 26
  • 34
0

Maybe this post can help.
I've used the annotation .Cascade.SaveUpdate().
My case was with a hasone in the parent putting the annotation on both sides

Obs: Language PT-BR

Community
  • 1
  • 1
Pedro
  • 1