Reputation: 659
How can I cast from
Expression<Func<T, bool>> predicate
to
Expression<Func<SomeType, bool>> predicate
?
Couldn't find a way so far. Or at least create a new Expression<Func<SomeType, bool>>
by using the first one's string representation of the predicate.
If it helps, T
is limited to types implementing ISomeInterface
, and SomeType
implements it.
LE: further clarification
The interface is something like:
public interface ICacheable
{
List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable;
}
then you have
public partial class Video : ICacheable
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
// implementation here that returns the actual List<Video>
// but when I try to query the dbcontext I can't pass a predicate with type T, I have to cast it somehow
List<Video> videos = db.Videos.Where(predicate).ToList(); // not working
}
}
then you have:
public class RedisCache
{
public List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
List<T> objList = // get objects from cache store here
if(objList == null)
{
List<T> objList = GetObjects<T>(predicate);
// cache the result next
}
return objList;
}
}
I use the above from any class like so:
// If the list is not found, the cache store automatically retrieves
// and caches the data based on the methods enforced by the interface
// The overall structure and logic has more to it.
List<Video> videos = redisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = redisCache.GetList<Image>(v => v.Title.Contains("another text"));
And I would extend this to any type of object I need to be cachable, with methods that will allow the Cache store to automatically retrieve an entity or list of entities if they are not found in cache. I might be doing this completely wrong though.
Upvotes: 4
Views: 4004
Reputation: 8280
I'm not up to scratch on my Entity Framework, but I know that the DatabaseContext
within LINQ has a GetTable<T>
which returns the table based on the generic. If "GetTable equivalent for ObjectContext" is anything to go by, it's also available in EF?
To make your statement truly generic, you could try this:
public MyBaseObject<T>
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
return db.CreateObjectSet<T>().Where(predicate).ToList();
}
}
public partial class Image : MyBaseObject<Image>, ICacheable
{
}
public partial class Video : MyBaseObject<Video>, ICacheable
{
}
Upvotes: 1
Reputation: 15403
Here is something (extremely) basic which, I hope, might help you in the process of caching using generics.
// ICacheable interface is used as a flag for cacheable classes
public interface ICacheable
{
}
// Videos and Images are ICacheable
public class Video : ICacheable
{
public String Title { get; set; }
}
public class Image : ICacheable
{
public String Title { get; set; }
}
// CacheStore will keep all objects loaded for a class,
// as well as the hashcodes of the predicates used to load these objects
public class CacheStore<T> where T : ICacheable
{
static List<T> loadedObjects = new List<T>();
static List<int> loadedPredicatesHashCodes = new List<int>();
public static List<T> GetObjects(Expression<Func<T, bool>> predicate)
{
if (loadedPredicatesHashCodes.Contains(predicate.GetHashCode<T>()))
// objects corresponding to this predicate are in the cache, filter all cached objects with predicate
return loadedObjects.Where(predicate.Compile()).ToList();
else
return null;
}
// Store objects in the cache, as well as the predicates used to load them
public static void StoreObjects(List<T> objects, Expression<Func<T, bool>> predicate)
{
var hashCode = predicate.GetHashCode<T>();
if (!loadedPredicatesHashCodes.Contains(hashCode))
{
loadedPredicatesHashCodes.Add(hashCode);
loadedObjects = loadedObjects.Union(objects).ToList();
}
}
}
// DbLoader for objets of a given class
public class DbStore<T> where T : ICacheable
{
public static List<T> GetDbObjects(Expression<Func<T, bool>> predicate)
{
return new List<T>(); // in real life, load objects from Db, with predicate
}
}
// your redis cache
public class RedisCache
{
public static List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T:ICacheable
{
// try to load from cache
var objList = CacheStore<T>.GetObjects(predicate);
if(objList == null)
{
// cache does not contains objects, load from db
objList = DbStore<T>.GetDbObjects(predicate);
// store in cache
CacheStore<T>.StoreObjects(objList,predicate);
}
return objList;
}
}
// example of using cache
public class useRedisCache
{
List<Video> videos = RedisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = RedisCache.GetList<Image>(i => i.Title.Contains("another text"));
}
// utility for serializing a predicate and get a hashcode (might be useless, depending on .Equals result on two equivalent predicates)
public static class PredicateSerializer
{
public static int GetHashCode<T>(this Expression<Func<T, bool>> predicate) where T : ICacheable
{
var serializer = new XmlSerializer(typeof(Expression<Func<T, bool>>));
var strw = new StringWriter();
var sw = XmlWriter.Create(strw);
serializer.Serialize(sw, predicate);
sw.Close();
return strw.ToString().GetHashCode();
}
}
Upvotes: 1