NWorkspace, querying API

OK, here I talked about the basic idea, and here I talked about the basic API, except for querying. It's now time to deal with querying.

My idea is that the NWorkspace assembly provides an interface called IQuery and a simple implementation of that interface called Query. You can use Query directly if you want to for, say, fetching all the customers with the name Volvo (OK, there'll probably only be just the one, but that's not important here):

NWorkspace.IQuery q = new Query(typeof(Customer));
q.AddCriterion(new Criterion("Name", Operator.Equal, "Volvo"));
IList aCustomerList = _ws.GetByQuery(q);

Here is an alternative for the last line above, if you prefer working with type safe lists:

CustomerList aCustomerList = new CustomerList();
_ws.GetByQuery(q, aCustomerList);

I could say more about, say, sorting, but I think you get the picture.

It's also possible to wrap the Query class in a custom query class in the Domain Model. (Of course you could skip wrapping Query and provide your own implementation of IQuery.) I think it's a nice solution to add a library of type safe queries to the Domain Model. Doing this would mean that the API for the consumer would become easier to use, for example. This is how the query could look like with a custom CustomerQuery:

CustomerQuery q = new CustomerQuery();
q.Name.Eq("Volvo");
IList aCustomerList = _ws.GetByQuery(q);

OK, this simple example was not a big deal, but in real situations if you create custom queries you can provide lots of power to the consumers and a very simple API at the same time. You also have the query definitions where I think they belong the most, being in the Domain Model, and they are (to a large degree) transparent to the OR Mapper that is used.

Yep, in a way the whole NWorkspace API will be the least common denominator. Saying that, I won't start the design by investigating what the different mappers can do. Instead I will just create a simple API that I want to have for dealing with the most common situations. Then, if you need power, you always have the possibility to go directly to the mapper. You should, of course, try to avoid that if you have decided to use a higher-level abstraction. However, when you do need to you can, just as you can skip the OR Mapper (for most mappers) and go directly to SQL when you really need to.

Comments?