Showing posts with label bidirectional associations. Show all posts
Showing posts with label bidirectional associations. Show all posts

Saturday, May 10, 2008

Revisiting bidirectional association helpers

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, to, 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 nongeneric 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.

Thursday, December 6, 2007

Collections for WPF and NHibernate

My current programming project is on the Microsoft .NET platform, and I'm writing code in the C# language. I'm using NHibernate — a popular object/relational mapping tool — in the data access layer, and Windows Presentation Foundation (WPF) for the user interface. One of the features making WPF so attractive is data binding. Although I was initially disappointed when I found out that NHibernate's collections don't work correctly out-of-the-box with WPF data binding, I soon found Gary DeReese's blog entry which provides a (partial) solution. Gary's "NotifyingCollectionDemo" shows how a custom collection type can be built to rectify NHibernate's shortcoming. After studying how his ObservableList (which is actually an observable bag) was created relative to the NHibernate API, I began work on my own "ObservableCollections" project which includes three custom collection types: observable bag, observable list, and observable set.

I've finished creating these custom collection types, so you can download the result now (updated 2008-Dec-10) to use in your own projects. The zip archive contains a Visual Studio 2005 solution that includes three projects. The "ObservableCollections" project is the library containing the custom collections. The "ObservableCollections Demo" project is a WPF program that you can run to play with the contents of a sample set and sample list collection. And the "CoreHelpers" project contains some miscellaneous helper classes that I use in various projects. Before running the demo project, however, you'll need to do the following:
  • Add references to the library and demo projects, pointing to the following NHibernate assemblies on your computer (unless already in the GAC): NHibernate, Castle.DynamicProxy, Iesi.Collections, and log4net.

  • Change the absolute path of the database in the hibernate.cfg.xml file to match its location on your computer.
The "CoreHelpers" project includes a OneToManyAssocSync helper class that makes it easy to maintain in-memory the semantics of a one-to-many bidirectional association. The demo project shows how to use it. There is also a ManyToManyAssocSync class for easily maintaining many-to-many bidirectional associations. (See this blog entry for a note about the renaming of these classes from their former names.)