I am trying to implement caching mechanism for entities. And to use the entities correctly and seamlessly with the caching i need to detach the entity from the current context before i put it in a cache and attach it back the the new context when i get it from the cache. (My context lifetime is per http request)
The requirements are that -
This is my attempt at creating an EntityCache class - (ServerCache here is my wrapper class that pushes the object to ASP.NET cache)
public static class EntityCache
{
private static DbContext context
{
get
{
return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey];
}
}
private static void Detach(object entity)
{
var trackedEntity = entity as IEntityWithChangeTracker;
trackedEntity.SetChangeTracker(null);
((IObjectContextAdapter)context).ObjectContext.Detach(entity);
}
private static void Attach(object entity)
{
((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity);
}
public static void Remove(string key)
{
ServerCache.Remove(key);
}
public static object Get(string key)
{
object output = ServerCache.Get(key);
if (output != null)
Attach(output);
return output;
}
public static void ShortCache(String key, object data)
{
if (data != null)
{
Detach(data);
ServerCache.ShortCache(key, data);
}
}
public static void LongCache(String key, object data)
{
if (data != null)
{
Detach(data);
ServerCache.LongCache(key, data);
}
}
}
When i put an entity in the cache it is of type DynamicProxy and NOT the real class.
Attaching doesnt work at all - i get an exception that i cannot case object that is of type Dynamic_{blahblah} to IEntityWithKey.
I just saw these examples of attach and detach online and tried them, I am open to any new implementation of the Attach/Detach methods here.
Thank you.
Follow up question -
context.Entry(entity).State = EntityState.Detached;
Works, but makes all the navigational properties that are loaded NULL, how do we make it keep the navigational properties and NOT replace(or lose) them with NULL when we detach from context.
IEntityWithKey
is interface for other types of entities. It is for "big" entities. For example EntityObject
implement this interface. These entities are not considered as POCO and are not supported by DbContext
API.
If you want to use IEntityWithKey
your classes must implement it - it is not something that would happen automatically.
Correct attaching with DbContext
API should be:
dbContext.Set(typeof(entity)).Attach(entity);
and this should hopefully also work:
dbContext.Entry(entity).State = EntityState.Unchanged;
Correct detaching with DbContext
API should be:
dbContext.Entry(entity).State = EntityState.Detached;
Also it is better to you generic methods instead of object
.