0

Given the following over-simplified code:

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

public class Parent
{
    public List<Child> Children { get; set; }
 }

In my consumer code, I'd have:

 parent.Children.Add(child);

This does not set the child.Parent, until I call db.SaveContext();

I see situations in which this is a problem, e.g. chaining a couple of operations on the same object before saving.

My question is, should I be doing this instead:

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

      public void SetParent(Parent parent) {
         if (this.Parent != null) { this.Parent.Children.Remove(this); }

         parent.Children.Add(this);
         this.Parent = parent;
      }
 }

Please note the code snippet is just for illustrative purpose.

Generally my question is, should I handle the relational fix up myself, instead of relying on EF.

hyankov
  • 4,049
  • 1
  • 29
  • 46
  • why would you want to handle that? what is your concern? – Alexander Taran Dec 03 '16 at 20:23
  • My concern is that unless I `save`, the object is not in a correct state. It just seems wrong to rely on EF to fix the mess. – hyankov Dec 03 '16 at 21:35
  • It is not the mess. You just don't know the Ids of the entities. If I remember correctly - ef with ObjectContext (prior to dbContext) was douing all that - referencing other sides of nav properties, assigning Ids (if known) etc. – Alexander Taran Dec 04 '16 at 06:23

1 Answers1

0

For simplicity, I would try to avoid the kind of chained operations that would require you to have to do this, but I don't think there is anything wrong with doing it if you need it.

A suggestion: Do not directly expose the Children collection in your Parent class, make its setter method private or protected, and add methods to add and remove Children elements in the Parent class. This is the way to ensure that the logic to set Child parent is always executed whenever the collection changes.

public class Parent
{
    public List<Child> Children { get; protected set; }

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

    public void RemoveChild(Child child)
    {
        Children.Remove(child);
        child.Parent = null;
    }
}
Diana
  • 2,186
  • 1
  • 20
  • 31
  • Thanks, but making the `setter` non-public does not protect the collection from changes. On the other hand, we can't have `IReadOnlyCollection` as EF navigational property. Stalemate. – hyankov Dec 03 '16 at 21:37
  • The goal is not to protect the collection against changes, but to make sure the required `child.Parent = newParent` gets executed when those changes happen. And EF can deal with navigation properties with only a public getter. Try this: `public virtual ICollection Children { get; } = new HashSet();` – Diana Dec 03 '16 at 21:51
  • Having the two methods `AddChild`and `RemoveChild` without protecting the `Children` property is like putting a solid door in the middle of a grass field. – hyankov Dec 03 '16 at 22:06
  • Then protect the property. You can map private properties as explained [here](http://stackoverflow.com/a/13810766/1182515). – Diana Dec 03 '16 at 23:12
  • [Here](https://owencraig.com/mapping-but-not-exposing-icollections-in-entity-framework/) you have a way to do it, exposing a truly protected `Children` property where you can only add elements through the `AddChild` method. – Diana Dec 03 '16 at 23:21