using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace PetaPoco { public static class PetaPocoRelationExtensions { public static List FetchOneToMany(this Database db, Func key, Sql Sql) { var relator = new Relator(); return db.Fetch((a, b) => relator.OneToMany(a, b, key), Sql); } public static List FetchManyToOne(this Database db, Func key, Sql Sql) { var relator = new Relator(); return db.Fetch((a, b) => relator.ManyToOne(a, b, key), Sql); } public static List FetchManyToOne(this Database db, Func key, Sql Sql) { var relator = new Relator(); return db.Fetch((a, b, c) => relator.ManyToOne(a, b, c, key), Sql); } public static List FetchManyToOne(this Database db, Func key, Sql Sql) { var relator = new Relator(); return db.Fetch((a, b, c, d) => relator.ManyToOne(a, b, c, d, key), Sql); } public static List FetchOneToMany(this Database db, Func key, string sql, params object[] args) { return db.FetchOneToMany(key, new Sql(sql, args)); } public static List FetchManyToOne(this Database db, Func key, string sql, params object[] args) { return db.FetchManyToOne(key, new Sql(sql, args)); } public static List FetchManyToOne(this Database db, Func key, string sql, params object[] args) { return db.FetchManyToOne(key, new Sql(sql, args)); } public static List FetchManyToOne(this Database db, Func key, string sql, params object[] args) { return db.FetchManyToOne(key, new Sql(sql, args)); } } public class Relator { private Dictionary existingmanytoone = new Dictionary(); private List properties = new List(); private PropertyInfo property1, property2, property3; public T ManyToOne(T main, TSub1 sub, Func idFunc) { property1 = GetProperty(property1); sub = GetSub(main, sub, idFunc); property1.SetValue(main, sub, null); return main; } public T ManyToOne(T main, TSub1 sub1, TSub2 sub2, Func idFunc) { property1 = GetProperty(property1); property2 = GetProperty(property2); sub1 = GetSub(main, sub1, idFunc); sub2 = GetSub(main, sub2, idFunc); property1.SetValue(main, sub1, null); property2.SetValue(main, sub2, null); return main; } public T ManyToOne(T main, TSub1 sub1, TSub2 sub2, TSub3 sub3, Func idFunc) { property1 = GetProperty(property1); property2 = GetProperty(property2); property3 = GetProperty(property3); sub1 = GetSub(main, sub1, idFunc); sub2 = GetSub(main, sub2, idFunc); sub3 = GetSub(main, sub3, idFunc); property1.SetValue(main, sub1, null); property2.SetValue(main, sub2, null); property3.SetValue(main, sub3, null); return main; } private PropertyInfo GetProperty(PropertyInfo property) { if (property == null) { property = typeof (T).GetProperties() .Where(x => typeof (TSub) == x.PropertyType && !properties.Contains(x.Name)) .FirstOrDefault(); if (property == null) ThrowPropertyNotFoundException(); properties.Add(property.Name); } return property; } private TSub GetSub(T main, TSub sub, Func idFunc) { object existing; if (existingmanytoone.TryGetValue(idFunc(main) + typeof (TSub).Name, out existing)) sub = (TSub) existing; else existingmanytoone.Add(idFunc(main) + typeof(TSub).Name, sub); return sub; } private object onetomanycurrent; public T OneToMany(T main, TSub sub, Func idFunc) { if (main == null) return (T)onetomanycurrent; if (property1 == null) { property1 = typeof(T).GetProperties().Where(x => typeof(ICollection).IsAssignableFrom(x.PropertyType)).FirstOrDefault(); if (property1 == null) ThrowPropertyNotFoundException>(); } if (onetomanycurrent != null && idFunc((T)onetomanycurrent).Equals(idFunc(main))) { ((ICollection)property1.GetValue((T)onetomanycurrent, null)).Add(sub); return default(T); } var prev = (T)onetomanycurrent; onetomanycurrent = main; property1.SetValue((T)onetomanycurrent, new List { sub }, null); return prev; } private static void ThrowPropertyNotFoundException() { throw new Exception(string.Format("No Property of type {0} found on object of type: {1}", typeof(TSub1).Name, typeof(T).Name)); } } }