using System; namespace Marr.Data { public interface ILazyLoaded : ICloneable { bool IsLoaded { get; } void Prepare(Func<IDataMapper> dataMapperFactory, object parent); void LazyLoad(); } /// <summary> /// Allows a field to be lazy loaded. /// </summary> /// <typeparam name="TChild"></typeparam> public class LazyLoaded<TChild> : ILazyLoaded { protected TChild _value; public LazyLoaded() { } public LazyLoaded(TChild val) { _value = val; IsLoaded = true; } public TChild Value { get { LazyLoad(); return _value; } } public bool IsLoaded { get; protected set; } public virtual void Prepare(Func<IDataMapper> dataMapperFactory, object parent) { } public virtual void LazyLoad() { } public static implicit operator LazyLoaded<TChild>(TChild val) { return new LazyLoaded<TChild>(val); } public static implicit operator TChild(LazyLoaded<TChild> lazy) { return lazy.Value; } public object Clone() { return MemberwiseClone(); } } /// <summary> /// This is the lazy loading proxy. /// </summary> /// <typeparam name="TParent">The parent entity that contains the lazy loaded entity.</typeparam> /// <typeparam name="TChild">The child entity that is being lazy loaded.</typeparam> internal class LazyLoaded<TParent, TChild> : LazyLoaded<TChild> { private TParent _parent; private Func<IDataMapper> _dbMapperFactory; private readonly Func<IDataMapper, TParent, TChild> _query; private readonly Func<TParent, bool> _condition; internal LazyLoaded(Func<IDataMapper, TParent, TChild> query, Func<TParent, bool> condition = null) { _query = query; _condition = condition; } public LazyLoaded(TChild val) : base(val) { _value = val; IsLoaded = true; } /// <summary> /// The second part of the initialization happens when the entity is being built. /// </summary> /// <param name="dataMapperFactory">Knows how to instantiate a new IDataMapper.</param> /// <param name="parent">The parent entity.</param> public override void Prepare(Func<IDataMapper> dataMapperFactory, object parent) { _dbMapperFactory = dataMapperFactory; _parent = (TParent)parent; } public override void LazyLoad() { if (!IsLoaded) { if (_condition != null && _condition(_parent)) { using (IDataMapper db = _dbMapperFactory()) { _value = _query(db, _parent); } } else { _value = default(TChild); } IsLoaded = true; } } public static implicit operator LazyLoaded<TParent, TChild>(TChild val) { return new LazyLoaded<TParent, TChild>(val); } public static implicit operator TChild(LazyLoaded<TParent, TChild> lazy) { return lazy.Value; } } }