The one-to-many and many-to-many helper classes in my ObservableCollections project make it easy to maintain in-memory the semantics of bidirectional associations, by keeping an association's references in sync in both directions. The way these helper classes are now, they work only in situations where the many-side is constrained as unique and is non-indexed, i.e., the corresponding collection is an ISet
. However, I've encountered a situation in my main project where an association's many-side is indexed, i.e., the corresponding collection is an IList
. So I'm revisiting the ObservableCollections project in order to accommodate this need.
Looking back at the bidirectional association helper classes after so much time, I realised how confusing the class and method names have been. So the first step was to rename them. For starters, I renamed the SetContainerToEntityAssocSync
class to OneToManyAssocSync
to reflect the more general (albeit incomplete although I will add support to the newly named OneToManyAssocSync
class for indexed collections, this more general name isn't completely applicable since I won't be adding support for non-unique collections as well.) desired applicability. And I renamed the SetContainerToSetContainerAssocSync
class to ManyToManyAssocSync
. After that, in the OneToManyAssocSync
class, I changed other occurrences of "setContainer
" to say "one
" or "oneSide
" since it has a multiplicity of one in the relationship. And I changed "entity
" to say "many
" or "manySide
" since it has a multiplicity of n in the relationship. Finally, I renamed some miscellaneous variable names so that they, too, will be consistent with this new terminology.
The next step was to modify the OneToManyAssocSync
class's UpdateOneSide
method, along with the ManyToManyAssocSync
class's UpdateOtherSide
method, as follows. The other side's collection must be cast not to ISet
, but to the ancestor type ICollection
which is common to both ISet
and IList
. I actually ended up using the generic ICollection<T>
since the non-generic version strangely lacks methods for adding, removing, and checking for containment of items. The code now works in cases the collection type is an IList
; however, it only works when the uniqueness constraint is being applied to the IList
, which is fine in the case of my main project. It will not, however, work for bags or lists with multiple occurrences of the same item. I included checks for this boundary condition.
Adrian loves facilitating suave user experiences via the latest and greatest GUI technologies such as Windows 8 Metro-style apps as well as WPF. More generally, he finds joy in architecting software that is easy to comprehend and maintain. He does so by applying design patterns at the top-level, and by incessantly refactoring code at lower levels. He's always interested in hearing about opportunities for full or part-time development work. He resides in Pennsylvania but can potentially travel anywhere in the country. (Writing about himself in the third-person is Adrian's new hobby.)