I have a repository layer that deals with LINQ to SQL autogenerated entities. These eventually get mapped into domain-friendly types on the surface. I'd now like to provide some more sophisticated querying capabilities for the client code, and that client code knows only about the domain object types.
I'd like to implement this with the Query Object pattern (as named in Martin Fowler's Patterns of Enterprise Application Architecture), but allowing the client code to use lambda expressions with domain types. Under the covers, I'd like to convert the domain-aware lambda expression into a database-aware lambda and send this converted expression to the repository for execution against the database with LINQ to SQL.
I currently have a poor-man's implementation that restricts the client's mapping ability to simple properties, but I'd like to open it up a little to more sophisticated querying. I'm not sure how I would approach this with AutoMapper or any other existing mapping tool, nor am I sure OTTOMH how I could do it with homegrown code.
Here's the kind of functionality I'd like:
// Example types to be interconverted...
// DomainId should map to DataEntityId and vice versa
// DomainName should map to DataEntityName and vice versa
public class DomainType
{
public int DomainId { get; set; }
public string DomainName { get; set; }
}
public class DataEntityType
{
public int DataEntityId { get; set; }
public string DataEntityName { get; set; }
}
// And this basic framework for a query object.
public class Query<T>
{
public Query(Func<T, bool> expression) { ... }
public Func<T, bool> Query { get; }
}
// And a mapper with knowledge about the interconverted query types
public class QueryMapper<TSource, TDestination>
{
public void SupplySomeMappingInstructions(
Func<TSource, object> source, Func<TDestination, object> dest);
public Query<TDestination> Map(Query<TSource> query);
}
// And a repository that receives query objects
public class Repository<T>
{
public IQueryable<T> GetForQuery(Query<T> query) { ... }
}
With the ultimate goal of getting something like this to work:
// a repository that is tied to the LINQ-to-SQL types.
var repository = new Repository<DataEntityType>(...);
// a query object that describes which domain objects it wants to retrieve
var domain_query = new Query<DomainType>(item => item.DomainId == 1);
// some mapping component that knows how to interconvert query types
var query_mapper = new QueryMapper<DomainType, DataEntityType>();
query_mapper.SupplySomeMappingInstructions(
domain => domain.DomainId, data => data.DataEntityId);
query_mapper.SupplySomeMappingInstructions(
domain => domain.DomainName, data => data.DataEntityName);
IQueryable<DataEntityType> results =
repository.GetForQuery(query_mapper.Map(domain_query));
My questions are really this, I think:
- Is it feasible to create such a mapper, and if so...
- Is it feasible to do so with a tool like AutoMapper, and if so...
- Is it possible to take advantage of the AutoMapper mapping that I already have that interconverts
DomainType
andDataEntityType
or would I need to explicitly mapQuery<DomainType>
toQuery<DataEntityType>
?
I ultimately want to do this to have the flexibility of using arbitrary mapping functions that are not necessarily simple object properties.