.norm was created to be a simple object mapping layer. It's not a silver bullet.
It does have benefits
But, it also has limitations
- It heavily uses reflection which may be a problem if you require very high performance.
- It ignores fields or properties which are user defined types.
These limitations are by design. By heavily using reflection it is possible to allow usage with little or no set up. This can add velocity to the start of a project. Later in the project, if performance is critical you can look for optimization opportunities.
.norm could address the issue of working with graphs of objects; however, the complexity may not be worth the pay off. Consider for example you have a Foo class that has a Bar property. Persisting Foo and Bar is simple. But, if Foo takes a Bar as a constructor argument things become much more complicated. Now, to return an instance of Foo you need an instance of Bar registered to DataGateway.
There are ways to work around this issue.
- Simply add a default constructor.
- Before returning an object (Foo) you could register all it's properties that are user defined types (Bar). However, there is no way to ensure that the object that was persisted as the property of type Bar was also the constructor argument of type Bar.
- Change Foo's dependency from a Bar to a BarFactory. But, now each user defined type will also need a factory. Register the BarFactory to satisfy Foo's constructor at creation time. This could clutter your domain. .norm is not supposed to be intrusive enough to force design issues.
- Add a boolean to the ColumnAttribute that specified if the decorated property (or field) should be registered as a dependency.
If .norm does become object graph friendly option 2 will likely not be implemented because it would complicate usage without clear benefit. Option 4 is quite possible, but it is just one of the issues related to object graph support. Cascading deletes is another obvious issue that will need to be dealt with. Cascading delete can be handled via attributes also, but at some point to the domain objects become to cluttered with orm code.
Remaining unfriendly to object graphs may be a superior alternative. .norm can be used as a base for a custom data mapping layer. Again, .norm isn't a silver bullet. .norm is a simple framework that automates simple tasks. When situations become more complex, classes can wrap .norm functionality and enforce the persistence/finding logic.
Consider this applied to the above Foo and Bar problem. Foo and Bar can both be persisted by .norm. But, Foo needs a Bar instance as a constructor argument. If you wrote a FooMapper class it could handle Foo persistence and persistence all of the child objects of Foo. Additionally, FooMapper could create (via .norm) or get from a factory the Bar dependency, register it with DataGateway and then return the Foo class correctly hydrated. Additionally, using FooMapper to delete could ensure that the necessary child objects are also removed.
Regardless of implementation, abstracting the dependency resolution to another class clearly has benefits. The alternative relies on .norm to make complex decisions (which increases the likelihood of mistakes).
Does this mean that .norm will not support object graphs? Absolutely not. If object graph comaptibility is required to increase adoption it will clearly be added. But, not until it's clear this is a widely requested feature.