So where we left off we were getting pretty close to a decent projection engine, with the slight caveat that we have to build up some atrociously long, dependency ridden projection dictionaries for the whole thing to work. Well I have gone through a few more iterations at this point and those dependencies are now gone, as well as a slight cleanup of usage syntax. The entire thing is really simple, so lets dig into the code:
First of all we need some sort of Projection Profile that we can tuck into our model.
public abstract class Profile<TSource, TDest> {
public Expression<Func<TSource, TDest>> Projection { get; private set; }
public void CreateMap(Expression<Func<TSource, TDest>> Projection) {
this.Projection = Projection;
}
}
This lets us create a nested class in our model, like so:
public class ProjectionModel {
...
public class Profile : Profile<Model, ProjectionModel> {
public Profile() {
CreateMap(o => new ProjectionModel {
...
});
}
}
}
Lastly, our revised 3 projection methods for converting IQueryables, IEnumerables and instances of our projection models wrapped into a neat extension class:
public static class ProjectionModelExtension {
public static TDest Project<TSource, TDest>(this TSource Model, Profile<TSource, TDest> Profile) {
if (null == Model || null == Profile) {
return default(TDest);
}
return Profile.Projection.Compile().Invoke(Model);
}
public static IEnumerable<TDest> Project<TSource, TDest>(this IEnumerable<TSource> List, Profile<TSource, TDest> Profile) {
if (null == List || null == Profile) {
return null;
}
Func<TSource, TDest> p = Profile.Projection.Compile();
return List.Select(p);
}
public static IQueryable<TDest> Project<TSource, TDest>(this IQueryable<TSource> Query, Profile<TSource, TDest> Profile) {
if (null == Query || null == Profile) {
return null;
}
Expression<Func<TSource, TDest>> p = Profile.Projection;
return Query.Select(p);
}
}
When you put all that together you can use the following syntax:IEnumerables
IEnumerables<Model> list;
IEnumerables<ProjectionModel> plist = list.Project(new ProjectionModel.Profile());
IQueryables
IQueryable<Model> query;
IQueryable<ProjectionModel> pquery = query.Project(new ProjectionModel.Profile());
Single Models
Model m;
ProjectionModel p = m.Project(new ProjectionModel.Profile());
It's that simple! So enjoy and have fun!
No comments:
Post a Comment