Skip to content

Instantly share code, notes, and snippets.

@JeremySkinner
Created January 23, 2011 21:21
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JeremySkinner/792450 to your computer and use it in GitHub Desktop.
Save JeremySkinner/792450 to your computer and use it in GitHub Desktop.
A little strongly-typed wrapper around WebMatrix.Data - this is now its own project at https://github.com/JeremySkinner/WebMatrix.Data.StronglyTyped
// WebMatrix.Data's Query method returns an IEnumerable<dynamic>
// While this is great for simple scenarios, if you want to add behaviour to your DB objects
// then it can be a pain. Here's a simple wrapper that adds a strongly-typed Query method
// This is a simple implementation and could be improved.
// Represents a table in the database
public class User {
public int Id { get; set; }
public string Name { get; set; }
}
// Demo code
internal class Program {
static void Main(string[] args) {
using (var db = Database.Open("Test")) {
var users = db.Query<User>("select * from Users");
foreach (var user in users) {
Console.WriteLine(user.Id + " " + user.Name);
}
}
Console.ReadKey();
}
}
public static class DataExtensions {
public static IEnumerable<T> Query<T>(this Database db, string commandText, params object[] args) {
var queryResults = db.Query(commandText, args);
var mapper = Mapper<T>.Create();
return (from DynamicRecord record in queryResults select mapper.Map(record)).ToList();
}
}
public class Mapper<T> {
private Func<T> factory;
private Dictionary<string, Action<T, object>> setters = new Dictionary<string, Action<T, object>>();
private static Lazy<Mapper<T>> _instance = new Lazy<Mapper<T>>(() => new Mapper<T>());
private Mapper() {
factory = CreateActivatorDelegate();
foreach (var property in typeof(T).GetProperties()) {
if (property.CanWrite) {
setters[property.Name] = BuildSetterDelegate(property);
}
}
}
public T Map(DynamicRecord record) {
var instance = factory();
foreach(var column in record.Columns) {
Action<T, object> setter;
if(setters.TryGetValue(column, out setter)) {
setter(instance, record[column]);
}
}
return instance;
}
public static Mapper<T> Create() {
return _instance.Value;
}
private static Func<T> CreateActivatorDelegate() {
return CreateActivatorDelegate(typeof(T).GetConstructor(Type.EmptyTypes));
}
private static Func<T> CreateActivatorDelegate(ConstructorInfo constructor) {
return Expression.Lambda<Func<T>>(Expression.New(constructor)).Compile();
}
private static Action<T, object> BuildSetterDelegate(PropertyInfo prop) {
var instance = Expression.Parameter(typeof(T), "x");
var argument = Expression.Parameter(typeof(object), "v");
var setterCall = Expression.Call(
instance,
prop.GetSetMethod(true),
Expression.Convert(argument, prop.PropertyType));
return (Action<T, object>)Expression.Lambda(setterCall, instance, argument).Compile();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment