0

I want to cache my entities to avoid database interactions where possible. When I do something like:

public IList<Website> Get()
{
    //The `_cacheManager.Get` just retrieves the object from an `ObjectCache` instance based on key.
    return _cacheManager.Get(CcCacheWebsiteAll, () => _websiteRepository.Table.ToList());
}

I am running into issues when retrieving a value from the cache and assigning it to a new object that requires an instance of that type.

For instance:

var store = new Store();
store.Name = "something";
store.Website = _websiteService.Get().FirstOrDefault();
_storeService.Insert(store);

//Where _storeService.Insert(store) is:

public void InsertStore(Store store)
{
    _storeRepository.Insert(store); //THIS will raise the error
}

I would have thought that calling ToList() on the Get() method would throw the instances into a new list and stop the issue but I'm not finding this when testing.

Does anyone have any suggestions?

Note: Just to make sure I only have one context, I disabled caching and everything is working as expected.

Edit

Store Service Ctor:

public StoreService(IRepository<Store> storeRepository)
{
    _storeRepository = storeRepository;
}

Website Service Ctor:

public WebsiteService(IRepository<Website> websiteRepository)
{
    _websiteRepository= websiteRepository;
}
webnoob
  • 15,747
  • 13
  • 83
  • 165
  • Your `_websiteRepository` is the same instance as your `_storeRepository` ? – Maarten Oct 23 '14 at 20:57
  • No, they are in different services. Basically, each one is `IRepository`, 'IRepository` so it's a wrapper for EF stuff. I assume that because you asked that, the `ToList()` should be sorting my issue out? If I know this should do it, I'll focus my efforts elsewhere. – webnoob Oct 23 '14 at 21:02
  • You can use `.ToList()` but that doesn't stop the dbcontext from tracking your instance. You have to detach it so the dbcontext stop tracking it, and more importantly, another dbcontext can start tracking it. I also think you shouldn't `.Insert(...)` it, but simple attach the instance to the other dbcontext. – Maarten Oct 23 '14 at 21:03
  • Oh! Does it just keep a reference to the object in the list then and not an actual copy? – webnoob Oct 23 '14 at 21:04
  • Yep, the dbcontext has a reference to the instance. Calling `.ToList()` doesn't remove that reference. – Maarten Oct 23 '14 at 21:05
  • Doh! Now to find out where I read that tip ^^. I'll find a way to detach the entities prior to caching and go from there in that case. Could you please post an answer and I'll reward you for your time? – webnoob Oct 23 '14 at 21:06

1 Answers1

2

You have said you have two contexts. If you use one context (lets call it context A) to load your entity, then that entity is tracked by context A. You cannot use that instance with another context (context B). So you have to detach your entity from context A, and attach your entity to context B.

The method to detach/attach entities from/to contexts have changed a bit with the versions of Entity Framework, but for EF6 I think this article and this SO question describes it pretty well.

Community
  • 1
  • 1
Maarten
  • 22,527
  • 3
  • 47
  • 68