DataQuery

Overview | Data Query | Modeling | Mapping

The corner stone is a class that implements IQueryable (Linq interfaces extending IEnumerable) named DataQuery.

Rather than using extension methods in the manner that Linq extends IQueryable and IEnumerable, in contrast, the DataQuery implements a subset of the Linq operators, instead of delegating to a referenced Extension namespace (The way Extension methods work).

The consequences and reasons are numerous, but let’s enumerate through several to provide some insight.

Extension Methods allow for extensions to object type (as opposed to class types) without inheritance. The benefit of adding instance methods to Interfaces is that they can serve as the default implementation, without requiring the concrete classes to override. Overriding is done by implementing. Because of these advantages it is also possible to inadvertently reference Namespaces with additional extensions that would create collision or undesired side effects.

Limitations

Use DataQuery instead of IQueryable otherwise the compiler will reference the Extension method implementations since IQueryable does not explicitly define any operations.

[Future]

This may change in the future, but because IQueryableProviders may be inconsistent in their expression composition. This is significant because the implementation re-writes part of the expression tree, mainly to replace ParameterExpression of T with ParameterExpression of K. A future implementation may become a full ExpressionVisitor in order to support IQueryable transparently. Implications of performance and other factors are unknown and the future direction may change from these original ideas.

Subordinates

Inheritance Support
Because domain objects can inherit from a query targeting the base class, it can only filter | access members in common.

The feature desired is an up cast to the derived subclass from the base query.

Luckily there is already a Linq operator for this type of behavior and a generic version OfType and OfType<T> respectively.

The usage may be...

Supertype SubType
Contact <-- Person
IDataQuery<Person> query = contactStore.Query().OfType<Person>()
	.Where(p=> p.LastName == “Smith”);

Without OfType method you would only be able to do
// Same signatures as IQueryable
IDataQuery<Contact> query = contactStore.Query().Where(c=> c.Id == 1);

Since LastName does not exist on Contact, but is defined in Person.


IStorageStrategy := object that handles CRUD operations for a particular type.

Query
Create
Save
Delete

ObjectMapping:= object containing converters | mappers that allow forward and backward transformations between 2 objects.

The ObjectMapping object uses two standard Delegates definitions from the System namespace.
Action<T1, T2> where T1 and T2 are input method parameters.
Converter<TInput,TOutput>

Implementations

Currently, the implementations of IDataQuery<T> are DataQuery<T> and DataQueryProxy<T,K> and as the name implies it relays supported Linq operators to an underlying IQueryable<K>. In this context K is another type.

[Foreseeably this would work with any underlying IQueryable, but known implementations have not been tested.]

The proxy delegates to the Linq provider of K. In order for this to work a transformation between T and K must be supplied, so that when the DataQuery<T> is enumerated (via the GetEnumerator method as definied by IEnumerable) and each K item returned by the enumerator, it is then transformed to T and finally returned to the client.

This implementation relies on several conventions.
1. T and K must have the same property names.
2. The common properties must be the same data type or be implicitly convertible.

Providers supported

Entity Framework Storage
Currently only the Entity Framework has been tested and implemented.

Benefits of approach

Enum query support
...
IDataQuery<Person> query = personQuery.Where(p=> p.Gender == Gender.Male);

Last edited Feb 10, 2010 at 9:19 PM by adev, version 3

Comments

No comments yet.