I have used NHibernate in previous enterprise applications but its complex setup and scattered documentation are pushing me to try to use the much simpler PetaPoco in my next application. The main issue I am facing is the implementation of transparent lazy loading to support the following scenario:
public class Customer {
public string CustomerName { get; set; }
public List<Order> Orders { get; set; } // Orders should be lazy-loaded
}
public class Order {
public Int32 OrderNumber { get; set; }
public List<Product> Products { get; set; } // Products should be lazy-loaded
}
public class Product {
public string ProductName { get; set; }
}
I gather that I need to use Castle DynamicProxy but I am struggling to understand how to implement the interceptor that will intercept calls to the getters and trigger the retrieval of the related orders or products. Also, once I have the interceptor, how do I ensure it gets used when I retrieve data using PetaPoco?
Any assistance would be greatly appreciated.
Thanks in advance.
Edit: @Groo: I was thinking of creating a layer above the PetaPoco select functions to add interceptors for related collections (using a custom attribute), e.g.:
public class ReferencedByAttribute : Attribute
{
public String ForeignKeyPropertyName { get; set; }
public ReferencedByAttribute(String foreignKeyPropertyName)
{
this.ForeignKeyPropertyName = foreignKeyPropertyName;
}
}
using Castle.DynamicProxy;
public class LazyLoadingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// TODO: Intercept first call to getter and retrieve related objects from the database
invocation.Proceed();
}
}
public class PetaPocoWrapper {
public List<T> Fetch<T>(String sql) {
PetaPoco.Database db = new PetaPoco.Database("connectionstring");
List<T> entities = db.Fetch<T>(sql);
ProxyGenerator generator = new ProxyGenerator();
foreach(T entity in entities)
{
foreach (PropertyInfo pi in entity.GetType().GetProperties())
{
if (pi.GetCustomAttributes(typeof(ReferencedByAttribute), true).Count() == 1) {
pi.SetValue(entity, generator.CreateClassProxy(pi.PropertyType, new LazyLoadingInterceptor()), null);
}
}
}
return entities;
}
}