This project is read-only.

CollectionChanged Behaviour

Feb 5, 2010 at 3:11 AM


I'm working on a project and we have quite a few Obtics queries daisy-chained together.  I'm trying to improve performance of how we're using Obtics, as whilst we're getting the correct results, our implementation is not very performant, particularly on our target hardware.  I will raise another discussion point for that shortly though when I can get a useful example together.  Whilst trying to get a feel for how Obtics works, I saw some strange behaviour that didn't seem very intuitive to me.  Like most of your code though, it's usually for a reason I just don't understand, so I was wondering if you could please explain it to me?

One of the things I thought of when trying to speed up was some mechanism for implementing bulk changes to Observable collections.  I created a class extending ObservableCollection with an AddRange method.  This suppressed CollectionChanged events until all items were added, then fired one event for the whole changeset.  Any regular additions, or additions of 1 item are processed normally.

If I'm adding them in bulk, my assumption was that Obtics would treat them in the same manner, and I would only have one change notification.  This proved to be incorrect, in fact when stepping into the Obtics code it actually changed the 1 NotifyCollectionChangedEventArgs for 50 added items, into 50 of the Obtics equivalent and handled them all individually.

Can you please run me through why this happens?  I would have assumed it would be more efficient in that instance where those items were changed to process them once together rather than each one individually?  As I said though, there is usually a reason I just don't understand :P

I've created a small test app which demonstrates what I'm talking about.  It basically generates items and adds them in bulk to our ObservableCollections in the Cache, similar to how our app reacts to data being pushed from the database.



Feb 5, 2010 at 3:14 AM

Hmm, I just realised I can't attach anything to a Discussion.  I didn't want to raise it as an Issue, as I'm more curious as to how/why it works this way as opposed to raising a bug.  

If you need the example, can you please send me an e-mail address for which I could forward it to?



Feb 5, 2010 at 12:33 PM

Hi Nathan,

There are a few reasons why Obtics treats every item change individualy.

The main is historical. In the past WPF (the original target platform) did not support multi-item change notifications and because single item updates are much simpler than multi item updates the choice was easy. The code to handle multi updates is more extensive and would increase the size of the library.

Only in quite simple queries will multi item updates be possible from source to target. As soon as you use Sort, Distinct or Group or have more complex interdependencies will the bulk updated range have to be broken up into discontinous individual updates.

I'm curious about the circumstances in which your queries do not perform well enough.

If enough can be gained from ranged updates, they could be (re-)introduced.




Feb 5, 2010 at 1:29 PM

Hi Thomas,

Thanks for the prompt reply.  I figured there would be a reason for it.  To be honest, the way our stuff is currently setup, there isn't going to be a huge benefit.  If you do happen to re-introduce it, there should be some benefit for us, but don't go out of your way on our account if you have more important things to do.  The only reason I asked is because I noticed it on one of the first queries I was looking for, and as we get a bulk load of data into the cache on startup, it showed itself first.

I'm currently working through a test application based on the original one I started with.  We have a hierarchy of objects from which we display a subset depending on what item is selected in the parent.   In the example I have been working on, there is a set of schools, which have a set of courses, which have a set of units, which in turn have students.  Each unit has roughly 20 students and there are 6000 in the collection I'm filtering over.  A straight LINQ query setting the visible students when a unit is selected takes around 12ms, but of course this doesn't react to changes, so it's no good to me.  The equivalent driven by my Obtics query takes around 350-400ms.  Initially, I was using a helper class that had been written already, which by default called Cascade() on the result.  Functionally this was fine, but meant it always took 350-400ms, and even more when not on my dev PC.  Once I removed the call to Cascade() and bound directly to the Value, initial changes were the same speed, but calls to previously visited nodes took ~6ms, effectively instant.  All my queries are setup in the constructor, so are only changed in relation to property changes.  Doing this was one of the initial changes I made and sped thinks up markedly.  

I'm out of the office until Monday, so I may post back when I've got something that would be useful to show you.  I've tried using "Compile" instead of "Execute" but it didn't provide any huge differences given all the queries are hooked up up front, and Execute isn't called after the app is setup.  I may get back to you with a test app if I can't achieve what I'm after.  Have a good weekend!





Feb 10, 2010 at 10:45 AM

Hi Nathan,

Great that you found ways to improve performance so significantly. I would like to know how the use or not of Cascade() gives such a hughe difference in your case. Could you provide some code examples?