using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; class DLinqCache { class Key { /// <summary> /// Sql command text possibly containing {n} parameters /// </summary> internal string CommandText; /// <summary> /// Command parameter values: scalar types present in sql server types like int, int?, decimal, decimal?, string, DateTime, DateTime?, /// float, bool, bool?, double. /// </summary> internal object[] Parameters; /// <summary> /// Entity types from which this query depends /// </summary> internal Type[] SourceTables; } static Dictionary<Key, object> cache; /// <summary> /// Main entry point for all cached non-linq queries. /// Remember query in cache. /// </summary> /// <param name="source">types whose or whose child types query is depending. /// Spectial values: /// null - volatile. query is not cached /// empty array - permanent. cache is cleared only on company cahnge or re-login or windws clear command. /// </param> public static IEnumerable<TEntity> ExecuteQuery<TEntity>(string command, Type[] src, params object[] prm) where TEntity : new() { // todo: implement weak reference cache? var key = new Key { SourceTables = src, CommandText = command, Parameters = prm }; if (cache != null) { if (src != null) { object res; if (cache.TryGetValue(key, out res)) return (IEnumerable<TEntity>)res; } } else { cache = new Dictionary<Key, object>(new KeyComparer()); } using (var db = new Database()) { IEnumerable<TEntity> tul = db.ExecuteQuery<TEntity>(command, prm); cache.Add(key, tul); return tul; } } static DataChanged( Type entity ) { foreach (var k in cache.Where(k => IsSubclassOf(k.Key.SourceTables, entity))) cache.Remove(k.Key); } class KeyComparer : IEqualityComparer<Key> { public bool Equals(Key x, Key y) { if (x.CommandText != y.CommandText) return false; if (x.SourceTables.Length != y.SourceTables.Length || x.Parameters.Length != y.Parameters.Length) return false; for (int i = 0; i < x.SourceTables.Length; i++) if (x.SourceTables[i] != y.SourceTables[i]) return false; for (int i = 0; i < x.Parameters.Length; i++) if (x.Parameters[i].ToString() != y.Parameters[i].ToString()) return false; return true; } public int GetHashCode(Key obj) { return obj.GetHashCode(); } } static bool IsSubclassOf(Type child, Type parent) { return child == parent || child.IsSubclassOf(parent); } static bool IsSubclassOf(Type[] childs, Type parent) { return childs.Any(c => IsSubclassOf(c, parent)); } }