Skip to content

IntendedUsage

Craig Fowler edited this page Feb 25, 2020 · 1 revision

The ORM API is designed as a way to cut down on some of the boilerplate that developers need to write in order to maintain a application which is easily testable & conforms to the SOLID principles.

The intention is that developers will be able to use this API for the majority of their interactions with the data-store. The most common CRUD operations may be performed using the IQuery, IPersister and optionally IEntityData interfaces. Where only these interfaces and the extension methods in the CSF.ORM are used, CRUD logic (including Linq queries) may be placed fairly safely within business logic projects. This logic remains unit-testable by swapping the implementations out for in-memory ones.

The issue with using the ORM directly

If developers wished to use (for example) NHibernate directly, then it would be problematic to mix query logic with business logic. The NHibernate 'native' Linq extension methods will throw exceptions if they are used with IQueryable<T> instances that were not created via NHibernate; the extension methods have hard-coded dependencies upon NHibernate implementation classes. This makes unit tests unworkable and forces the developer to write and maintain more integration tests instead. This is a more costly testing strategy and can also lead to other problems such as fragile or hard-to-comprehend tests.

In order to maintain testability and conform to SOLID principles, developers would need to add a new service interface/class to perform each operation. This facilitates separation from the logic which consumes it. This can cause oddities where, in some cases, the query forms an integral part of the logic. It is also an awful lot of boilerplate code which exists only to separate technological differences.

This need for separation can push developers toward adopting the repository pattern as a wrapper for the ORM. Whilst that's not necessarily incorrect, it limits the usefulness of the ORM. At worst it can cause issues of its own with the need for further boilerplate to cover for leaky abstractions.

Not a silver bullet

As with many technical solutions, this API is not a perfect/complete solution.

It's OK to use the ORM where necessary

There will almost certainly be times where developers need to use the ORM, such as NHibernate, directly. The API presented by the NuGet packages in this repository do not expose the full functionality of the ORM. It is intentionality limited to a subset which can be substituted for testing purposes.

This is OK; developers may create an assembly of ORM-implementation-logic. They can put more complex ORM interactions there, and use classes and interfaces to separate this logic from core domain/business logic. The packages in this repository are only intended to cater for the most common scenarios.

Integration tests are still important

Whilst using this library will allow developers to write unit tests for much of their querying/persistence logic, that doesn't mean that they should neglect integration tests.

An in-memory data store is not a perfect substitute for a real ORM and its implementation of Linq. Every ORM/Linq provider comes with its own quirks. The only way to be completely sure that a query will work as intended is to run it using the ORM, against a real database.

The benefit of using the packages in this repository is that developers may write many easy-to-comprehend unit tests to cover various permutations of logic. They should still write a lesser number of integration tests to verify that the query does in fact work as intended when in an environment more close to production.

Clone this wiki locally