I implemented cached DLinq ExecuteQuery method.
However some queries are run against database always because keys
are not found in cache.
Maybe equality comparer or other parts of implementation are wrong and/or
inefficient.
How to fix this code ?
Which is best way to create static ExecuteQuery method which caches all
queries during
application lifetime ?
Andrus.
using System;
using System.Collecti ons.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, objectcache;
/// <summary>
/// Main entry point for all cached non-linq queries.
/// Remember query in cache.
/// </summary>
/// <param name="source">t ypes 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<TEn tityExecuteQuer y<TEntity>(stri ng 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.TryGetVa lue(key, out res))
return (IEnumerable<TE ntity>)res;
}
}
else
{
cache = new Dictionary<Key, object>(new KeyComparer());
}
using (var db = new Database())
{
IEnumerable<TEn titytul = db.ExecuteQuery <TEntity>(comma nd,
prm);
cache.Add(key, tul);
return tul;
}
}
static DataChanged( Type entity ) {
foreach (var k in cache.Where(k =>
IsSubclassOf(k. Key.SourceTable s, entity)))
cache.Remove(k. Key);
}
class KeyComparer : IEqualityCompar er<Key>
{
public bool Equals(Key x, Key y)
{
if (x.CommandText != y.CommandText)
return false;
if (x.SourceTables .Length != y.SourceTables. Length ||
x.Parameters.Le ngth != y.Parameters.Le ngth)
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.Le ngth; 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(Ty pe child, Type parent)
{
return child == parent || child.IsSubclas sOf(parent);
}
static bool IsSubclassOf(Ty pe[] childs, Type parent)
{
return childs.Any(c =IsSubclassOf(c , parent));
}
}
However some queries are run against database always because keys
are not found in cache.
Maybe equality comparer or other parts of implementation are wrong and/or
inefficient.
How to fix this code ?
Which is best way to create static ExecuteQuery method which caches all
queries during
application lifetime ?
Andrus.
using System;
using System.Collecti ons.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, objectcache;
/// <summary>
/// Main entry point for all cached non-linq queries.
/// Remember query in cache.
/// </summary>
/// <param name="source">t ypes 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<TEn tityExecuteQuer y<TEntity>(stri ng 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.TryGetVa lue(key, out res))
return (IEnumerable<TE ntity>)res;
}
}
else
{
cache = new Dictionary<Key, object>(new KeyComparer());
}
using (var db = new Database())
{
IEnumerable<TEn titytul = db.ExecuteQuery <TEntity>(comma nd,
prm);
cache.Add(key, tul);
return tul;
}
}
static DataChanged( Type entity ) {
foreach (var k in cache.Where(k =>
IsSubclassOf(k. Key.SourceTable s, entity)))
cache.Remove(k. Key);
}
class KeyComparer : IEqualityCompar er<Key>
{
public bool Equals(Key x, Key y)
{
if (x.CommandText != y.CommandText)
return false;
if (x.SourceTables .Length != y.SourceTables. Length ||
x.Parameters.Le ngth != y.Parameters.Le ngth)
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.Le ngth; 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(Ty pe child, Type parent)
{
return child == parent || child.IsSubclas sOf(parent);
}
static bool IsSubclassOf(Ty pe[] childs, Type parent)
{
return childs.Any(c =IsSubclassOf(c , parent));
}
}