2

I (my classes) have a parent child releationship and I want to the child only to know the id of the parent.

That way if i only need the details of one child not the complete parent with the rest of the object graph will be loaded.

Because I have foreign key constraints active in the db I get violations when I save. To solve I need this two step approach:

class Child
{
    public virtual Guid IdParent { get; set; }
}

class Parent
{
    void AddChild(Child c)
    {
       c.IdParent = this.Id;
       this.childs.Add(c);
    }
}

var parent = new Parent()
session.Save(parent)   // now the parent has an id

var child = new Child(); 
parent.Add(child);  // child now knows the parent id

session.Save(child);

What I really want is

var parent = new Parent();
var child = new Child()
parent.AddChild(child);

session.Save(parent);

Is there a way to store the parent Id at the child after nhibernate knows the id? I also want to have foreign key checking active in the db.

Mapping of parent:

this.HasMany<Child>(x => x.childs)
                .Not.LazyLoad()
                .AsBag()
                .Inverse()
                .Cascade.AllDeleteOrphan()
                .KeyColumn("id_parent");
schoetbi
  • 12,009
  • 10
  • 54
  • 72

1 Answers1

1

Suggestion: I. what we would need is to change your C# entities. Child should (well there is no need to not) have the Parent as a reference:

class Child
{
    //public virtual Guid IdParent { get; set; }
    public virtual Parent Parent { get; set; }
}

And then we can use the full power of NHibernate, even in cases of the creation, when the Parent ID will be known, only after INSERT. NHibernate will be able to take that generated ID (once generated) and properly store it in the column "id_parent"

In case, that you do not want to publish that property, it could be made protected... and the IdParent could be readonly bug public

class Child
{
    public virtual Guid IdParent { get; set; }
    protected virtual Parent Parent { get; set; }
}

But still, we can properly mapp the Child to parent with a reference.

II. In case, that you won't change the mapping, and you will use cascade on HasMany (collection mapping) it still can work... but without the Inverse()

The inverse could work only, if the child does know about the parent... but not the parent ID. And why? becuase in case of creation of the Parent, the Parent ID in the moment of assigning to child (your AddChild method) does not have to be the proper one

Summary: C# is what we do have in our hands (while sometimes we are facing legacy DB). I would strongly suggest: change your model the most "standard" way. Bi-directional mapping and relation is the right way, which will later allow you powerful features like filtering/searching

III. Cascade summary:

This functionality is supported by NHibernate, and is called cascading. And it exactly does fit to your needs. see:

6.2. Mapping a Collection

<bag
   ...
   cascade="all|none|save-update|delete|all-delete-orphan"     (6)

(6) cascade (optional - defaults to none) enable operations to cascade to child entities

Say, there is mapping like this:

A snippet of mapping children collection:

<bag name="Children" inverse="true" cascade="all">
    <key column="parent_id"/>
    <one-to-many class="Child"/>
</bag>

And form that moment your desired syntax will save both, parent and children

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • I had cascading active but the problem is that my foreign key constraints will be broken. – schoetbi Jul 16 '14 at 06:27
  • I am trying to extend my answer, as you are extending the question ;) give me few sec... – Radim Köhler Jul 16 '14 at 06:32
  • Many thanks!!. The reason why I do not want to have a direct object reference is that it degraded performance. When I fetch one child teh parent and (1000) other childs are loaded. This is too slow. Lazy loading is unfortunatelly not an option. – schoetbi Jul 16 '14 at 06:35
  • Well I described my knowledge in the answer ;) We should use the lazy and correct/proper bi-directional mapping. If there is issue with loading other children... do not load parent (use projections) if children should be loaded - use `batch-size` feature: http://stackoverflow.com/a/20970816/1679310 – Radim Köhler Jul 16 '14 at 06:37
  • Although your answer is not what I hoped to hear I give you the green since it helped me a lot. Thanks. – schoetbi Jul 16 '14 at 06:45
  • Great if it helped at least a bit. Do not worry, please, NHibernate is really able to give you a lot.. but with some soft and gentle usage ;) really. Simply, try to play with and the more you will know it.. the more you gain.. for sure! ;) Enjoy NHibernate – Radim Köhler Jul 16 '14 at 06:46