Supress Loading of Children in the Hierarchy

Apr 19, 2011 at 11:38 PM

I am looking at implementing this feature, however, there are some caveats and am looking for community feedback before I proceed.

Most likely the implementation for suppressing the load of child elements will be based on a predicate-style invocation. As the serializer parses the tree, it will "ask" whether or not to de-serialize a particular child.

Here are the caveats:

1. I can do a Predicate<T> ("continue with this type?") or a Func<string,Type,bool> ("continue with this type under this property?") Property name is not currently tracked, only the position, so this will be an internal change but will likely be needed to handle the type versioning issue any way. If you had something like public property IList<Foo> MyList then each Foo would result in a call with property name "MyList" and type "foo." False would mean "don't serialize" and true would mean "serialize" and this would be the default for backwards compatibility. So, first question - Predicate<T> or Func<string,Type,bool>?

2. Because of the way Sterling serializes into a single stream, it won't be possible to skip sub-classes. Why? Because they are serialized directly into the stream. To skip a sub class and go to the next property would require the reader to parse the entire sub class hierarchy any way. Until we change the storage mechanism (i.e. using a file with offsets) this will not be possible and it wouldn't make sense to just stop de-serializing at the first child you don't want walked. This is only for sub-classes, it's not for "foreign-key" classes.

3. For foreign key classes, Sterling would still have to walk through all keys. So, if you had a IList<foo> with 100 items, it would have to create a list of 100 items. For each item, it would read the key, then instead of loading the child, just set that slot to null and move to the next. This will obviously be significantly faster than unrolling all child objects, but still means it doesn't just skip the list but in fact parses the list and then goes to the next property.

Essentially, you would only be able to suppress de-serialization of "foreign key" classes. I believe this is the scenario you are most likely to run into but wanted to solicit feedback before moving forward on an assumption. To be clear, if you defined two tables: Foo and Bar, then this:

public class Foo 
    public int Id { get; set; }
    public IList<Bar> Bars { get; set; }
    public IList<FooBar> Foobars { get; set; }

Would allow you to suppress loading all of the "Bar" instances (bool LoadChild("Bars",typeof(Bar)) because these are stored in separate areas, but you would still be forced to load the "FooBar" instances because these would be serialized inline with the Foo class.


Apr 19, 2011 at 11:40 PM

PS Also wondering if it makes sense to create an "empty" object with the key so you can fully load later - i.e. in the above, the Bars list if you suppress loading would still have Bar objects, but the only initialized property would be the key value. Then if you wanted to load Bar #3 you'd do var bar = database.Load<Bar>(Bars[2].Id);

Apr 20, 2011 at 2:02 AM

1: Func<string,Type,bool>!

But why do each instance in the list trigger a call? Can't we say "don't save the whole list" (but still walk the list for key stuff)? Or am I missing something?

2: No problems for me.

3: Makes sense. And with the "PS" addemdum, if I understand, you are saying that instead of storing "null" in the list, you could create instances with only the key set.

PS: It makes total sense for me, but having a way (IsLoaded property? meh) to tell if it's a loaded instance would be great. What happens if an instance for a key was previously loaded? Would that last instance be inserted in the list instead of an empty instance? Is there a cache involed here?

While I have your attention, can you tell me why get-only IList<T> properties aren't serialized? I hate having setters on such properties, furthermore when using lists like ObservableCollection<T> that can have subscribed event handlers. Can't a "clear+add" pattern be used when de-serializing?


Apr 21, 2011 at 6:30 AM
Edited Apr 21, 2011 at 6:52 AM

It shouldn't be better to pass to the LoadChild method the type of the parent class instead of the type of the class which is is going to be decided whether it has to be loaded or not.

I mean, for your sample instead of this:

 bool LoadChild("Bars",typeof(Bar))

the alternative I propose is this one:

bool LoadChild("Bars",typeof(Foo))

The reason is for the first one if you have a type which is reused in many different classes and the name of its property is repeated, you don't have enough granularity to determine which classes should load the child and which not. However, passing the parent type you are able to stablish exactly for which classes this child should be loaded.

Has any sense what I'm saying? Maybe now I'm not able to see the problems of this approach