Building on our past discussion (see Improving on POCO Properties and Improving on POCO Collections), let us look at how we can improve the implementation of associations between our domain objects.
In a standard POCO domain model, associations are handled as simple object references, or as lists of object references:
With this approach, you either need to use eager loading and bring everything into memory at once (not usually a good
idea, as often you end up loading far too much, with a significant cost in memory and time), or somehow force
lazy-loading into play. NHibernate provides near transparent support for lazy-loading by
requiring all public methods and properties to be virtual
and then creating a descending proxy class at runtime. While
not ideal, it’s one approach that works well within the limitations of POCO classes. A specialist helper class, however,
could elevate lazy-loading to a first class concept, one natively supported by the domain layer.
Introducing helper classes to manage these associations, our Customer
class declaration would look like this:
As before, this becomes a lot more interesting when we start looking at our helper classes. Here’s the Reference<T>
class, used when the association is single-valued.
The Loaded
property allows for code to check if the association has already been loaded, and perhaps to avoid
accessing the association. In common with our previous examples - the helper classes
(Property
)[/blog/201001/improving-poco-properties] and (DomainCollection
)[/blog/201001/improving-poco-collections] -
we have support for both dirty checking and transactionality.
For multi-valued associations, here’s the ReferencesMany<T>
class:
As we’ve seen before, the Loaded
property allows code to check to see if the association has been loaded into memory
before doing anything that would require a load. We have support for both dirty checking and transactionality; and
events provide a way for the parent instance to exert control over what happens to the association.
One special case that it’s useful to consider is the need to know how many instances are at the end of the association
- as when performing checks before deletion. For performance reasons, it can be useful to be able to find this out
directly from the database and without forcing the association to load. To support this, the
Size()
function counts the number of matching rows directly in the database. Code accessing the association has the choice of forcing a Load, by accessingCount()
, or bypassing it, by callingSize()
.
Using helper classes to represent domain associations gives your code a richer base, making it easier to express your business rules. A useful side effect is the additional information now available for an ORM to use when making database updates.
Comments
blog comments powered by Disqus