Cascading deletes

Aug 12, 2016 at 2:12 PM
Hello,

In our schema we have quite a few cascading deletes set up. Originally we expected to be able to do this in our EF config but eventually decided it was not possible.

I am guessing this is going to cause us problems if we start using the 'Second Level Cache'?

Actually, before submitting this post I've just read this http://efcache.codeplex.com/workitem/18
I'm guessing "Try invalidating cache for the related entity set if you enabled cascade delete to remove stale results from the cache" is the answer to my question?

This is quite frustrating - although of course I understand the blame here lies entirely with EF and not EFCache.

regards,
Jordan
Coordinator
Aug 14, 2016 at 12:23 PM
Yes, you would have to invalidate related entity sets manually. From what I remember the information about configured cascade deletes is not available to EF Cache. You could handle invalidating related entity sets by wrapping the class that implements ICache and inspecting entity sets passed to InvalidateSets method. If you find a set for which a cascade delete was set up you would invalidate cache for the related set in addition to forwarding the call to the wrapped ICache implementation.

Thanks,
Pawel
Aug 15, 2016 at 8:53 AM
moozzyk wrote:
From what I remember the information about configured cascade deletes is not available to EF Cache.
Oh dear! Good to know though - so we would have this problem even if we didn't have cascading deletes built into the schema?

moozzyk wrote:
You could handle invalidating related entity sets by wrapping the class that implements ICache and inspecting entity sets passed to InvalidateSets method. If you find a set for which a cascade delete was set up you would invalidate cache for the related set in addition to forwarding the call to the wrapped ICache implementation.
Ok thankyou - that sounds about the most elegant way to do with this.

However, this situation has very much tainted my view of Entity Framework. Plugging in a caching mechanism should be transparent - the last thing I really want to do is have to write a load of custom code for entities which have cascading deletes. This is a fairly large project with a domain model that contains over 100 entities, its going to be quite a job to do this, and the resulting code is going to be very brittle and prone to breaking if changes are made to the schema over time.

Apologies for the off topic rant because this is really about Entity Framework rather than EFCache, but the cascading delete problem is already far from ideal. You shouldn't have to add cascading deletes to the database schema, EF should deal with it. (IIRC EF actually behaves differently depending on whether objects are in memory or not. I might be wrong about that as it is a few years since I have investigated this).

As an alternative strategy would it be possible to only turn caching on for certain entities?

Again - no criticism of EFCache intended at all, and thankyou very much for your reply.

regards,
Jordan.
Coordinator
Aug 15, 2016 at 3:44 PM
Edited Aug 15, 2016 at 3:45 PM
This post tells me that EF will send DELETE commands for related entity sets only if any of the related entities has been loaded into the context. In that case result for related sets should be cleared. However, if the cache contains results for a related set/table but the context did not contain any entities from this set EF won't send the DELETE command for the related set and, as a result, the cache may contain stale results. In general the issue is that there are no hooks in EF that could be used to tune caching.

I would not recommend turning on caching for all entities (in retrospect I think it was a mistake to make the "cache all" policy the default policy). Instead, you should take a look at the your model/database and only cache results that are worth caching (e.g. results for long running queries that don't change often). You need to derive from the CahingPolicy and overwrite the CanBeCached method and return true for the entity sets for which you want the results to be cached.

Thanks,
Pawel
Aug 15, 2016 at 4:04 PM
Edited Aug 15, 2016 at 4:04 PM
moozzyk wrote:
This post tells me that EF will send DELETE commands for related entity sets only if any of the related entities has been loaded into the context. In that case result for related sets should be cleared. However, if the cache contains results for a related set/table but the context did not contain any entities from this set EF won't send the DELETE command for the related set and, as a result, the cache may contain stale results. In general the issue is that there are no hooks in EF that could be used to tune caching.
Yes this is exactly the behaviour I saw when I was investigating cascading deletes in EF (which was probably 18 months ago now).
At the time I thought it was a bug, so I registered a bug with microsoft, and they replied as said it was a "feature" that they couldn't fix in EF6 because they would risk breaking too much client code... however, apparently the next version of Entity Framework might fix this.
I would not recommend turning on caching for all entities (in retrospect I think it was a mistake to make the "cache all" policy the default policy). Instead, you should take a look at the your model/database and only cache results that are worth caching (e.g. results for long running queries that don't change often). You need to derive from the CahingPolicy and overwrite the CanBeCached method and return true for the entity sets for which you want the results to be cached.
Ok brilliant. I'll look into that.
many thanks,
Jordan.
Aug 17, 2016 at 1:43 PM
moozzyk wrote:
You need to derive from the CahingPolicy and overwrite the CanBeCached method and return true for the entity sets for which you want the results to be cached.
ps - is there any example code anywhere that does this? I'm looking at this now and it isn't immediately obvious to me what an entity set is.

I'm just about to add a break point in my CachingPolicy.CanBeCached override to have a look at what is available to me.

many thanks,
Jordan
Coordinator
Aug 19, 2016 at 4:37 PM
It's the Store Entity Set which should be equivalent to the table name in most cases (if you are using EDMX your Store Entity Set name can be different from the table name)