0

I have 2 entities:

public class Parent
{
    public virtual string Number { get; set; }
    public virtual IList<Child> Children { get; set; }
    public Parent()
    {
        Phones = new List<Child>();
    }
}
public class Child
{
    public virtual string Number { get; set; }
    public virtual Parent Parent { get; set; }
}

and mappings:
child

 public ChildMap()
        {
            Map(x => x.Number).Not.Nullable();
            References(x => x.Parent).Nullable().LazyLoad().Cascade.None();
        }

and parent

public ParentMap()
    {
        Map(x => x.Number).Not.Nullable();
        HasMany(x => x.Children).Inverse().Cascade.All();
    }

but when i insert children to parent, it goes with null in parent foreign key.

var p = rep.Get(g => g.Id == 1);
Enumerable.Range(0, 100).Select(s => new Child()
    {
        Number = s.ToString()
    }).ToList().ForEach(p.Children.Add);
rep.Update(p);
rep.Flush();

actualy everything like in post NHibernate fluent HasMany mapping inserts NULL Foreign key
But insert link like this test.Orders.Add(new Order("test") { Company = test }); absolutly not true way, so i need help, any ideas?

Community
  • 1
  • 1
Roar
  • 2,117
  • 4
  • 24
  • 39

3 Answers3

1

You have a bidirectional relationship set up between Parent and Child, but when you are adding a child to the Children collection on Parent, you are not setting the Parent property on each child.

The first thing I would recommend is question whether the relationship needs to be bidirectional - will typical usage work with Children independent of their Parents? Would you need to navigate the object graph in the direction from Child to Parent? Are both Parent and Child Aggregate Roots?

There are a few different ways to handle bidirectional relationships. One way is to define Add and Remove methods that add a Child to the Children collection and sets the Parent property on each child and to remove the ability to add a child directly to the collection, by making it an IEnumerable<Child> (or IReadOnlyCollection<Child>, or similar) for example with an IList<Child> backing field

public class Parent
{
    private IList<Child> _children;

    public Parent()
    {
        _children = new List<Child>();
    }

    public virtual string Number { get; set; }
    public virtual IEnumerable<Child> Children { get { return _children; } }

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

    public virtual void RemoveChild(Child child)
    {
        _children.Remove(child);
        child.Parent = null;
    }
}

public class Child
{
    public virtual string Number { get; set; }
    public virtual Parent Parent { get; set; }
}

The ParentMap should be modified to use the backing field

public ParentMap()
{
    Map(x => x.Number).Not.Nullable();
    HasMany(x => x.Children).Inverse()
                            .Cascade.All()
                            .Access.CamelCaseField(Prefix.Underscore);
}
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • It seems nice to do the same for the Parent in Child class. – mehdi.loa Apr 30 '13 at 10:21
  • 1
    @mehdi.loa `Parent` *owns* the relationship, so it makes sense to set the properties when adding to the child collection on `Parent`. – Russ Cam Apr 30 '13 at 13:34
  • @Roar what's not flexible? – Russ Cam Apr 30 '13 at 13:35
  • @RussCam i dont want to add additional methods, i need mapping which will get parent item for each children – Roar Apr 30 '13 at 13:37
  • @Roar This is the general way to do bi-directional relationships with NHibernate. If the relationship doesn't *need* to be bi-directional, remove the `Parent` property from `Child` and use what you have already; a foreign key to `Parent` table will be created on the `Child` table for you. – Russ Cam Apr 30 '13 at 13:47
0

change to:

Enumerable.Range(0, 100).Select(s => new Child()
    {
        Number = s.ToString(),
        Parent = p
    }).ToList().ForEach(p.Children.Add);
mehdi.loa
  • 579
  • 1
  • 5
  • 23
0

The answer is

public ParentMap()
    {
        Map(x => x.Number).Not.Nullable();
        HasMany(x => x.Children).Cascade.All();
    }

Without inverse

Roar
  • 2,117
  • 4
  • 24
  • 39