using System; using System.Text.Json.Serialization; using NLog; using NzbDrone.Common.Instrumentation; namespace NzbDrone.Core.Datastore { public interface ILazyLoaded : ICloneable { bool IsLoaded { get; } void Prepare(IDatabase database, object parent); void LazyLoad(); } /// /// Allows a field to be lazy loaded. /// /// [JsonConverter(typeof(LazyLoadedConverterFactory))] public class LazyLoaded : 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 static implicit operator LazyLoaded(TChild val) { return new LazyLoaded(val); } public static implicit operator TChild(LazyLoaded lazy) { return lazy.Value; } public virtual void Prepare(IDatabase database, object parent) { } public virtual void LazyLoad() { } public object Clone() { return MemberwiseClone(); } } /// /// This is the lazy loading proxy. /// /// The parent entity that contains the lazy loaded entity. /// The child entity that is being lazy loaded. internal class LazyLoaded : LazyLoaded { private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(LazyLoaded)); private readonly Func _query; private readonly Func _condition; private IDatabase _database; private TParent _parent; public LazyLoaded(TChild val) : base(val) { _value = val; IsLoaded = true; } internal LazyLoaded(Func query, Func condition = null) { _query = query; _condition = condition; } public static implicit operator LazyLoaded(TChild val) { return new LazyLoaded(val); } public static implicit operator TChild(LazyLoaded lazy) { return lazy.Value; } public override void Prepare(IDatabase database, object parent) { _database = database; _parent = (TParent)parent; } public override void LazyLoad() { if (!IsLoaded) { if (_condition != null && _condition(_parent)) { if (SqlBuilderExtensions.LogSql) { Logger.Trace($"Lazy loading {typeof(TChild)} for {typeof(TParent)}"); Logger.Trace("StackTrace: '{0}'", Environment.StackTrace); } _value = _query(_database, _parent); } else { _value = default; } IsLoaded = true; } } } }