25

Say I have a table or 2 that contains data that will never or rarely change, is there any point of trying to cache those data? Or will the EF context cache that data for me when I load them the first time? I was thinking of loading all the data from those tables and use a static list or something to keep that data in memory and query the in memory data instead of the tables whenever I need the data within the same context. Those tables I speak of contains typically a few hundred rows of data.

OKB
  • 705
  • 2
  • 14
  • 29

3 Answers3

21

The EF context will cache "per instance". That is, each instance of the DbContext keeps it's own independent cache of objects. You can store the resulting list of objects in a static list and query it all you like without returning to the database. To be safe, make sure you abandon the DbContext after you execute the query.

var dbContext = new YourDbContext();
StaticData.CachedListOfThings = dbContext.ListOfThings.ToList();

You can later use LINQ to query the static list.

var widgets = StaticData.CachedListOfThing.Where(thing => thing.Widget == "Foo");

The query executes the in-memory collection, not the database.

Ed Chapel
  • 6,752
  • 3
  • 25
  • 43
  • Can i add list of results directly in Cache collection? I mean HttpRuntime.Cache["MyKey"] = context.ListOfThings.ToList() – Laserson Jul 05 '11 at 12:25
  • @ed-chapel I don't why this is a good idea, there are more cases where the data that we want to cache changes rarely (but it still changes). Using your suggestion won't help when a change occurs, or am I missing something? – snajahi Sep 12 '13 at 08:30
  • 1
    @K-SaMa You are right, this does nothing to refresh the data. This solution merely prevents, as the OP asked, how to prevent repetitive calls. Detecting and updating the cache are different harder problems, not asked here. – Ed Chapel Sep 12 '13 at 09:38
12

You can check EF caching provider but be aware that caching in this way is performed strictly on query basis - so you must use the same query all the time to get cached data. If you use another query it will first be executed to be considered as cached and then you use it again to hit the cache. If you want to avoid this and cache data with ability to run any query on cached collection you must roll on your own solution (simply load data to list and keep it somewhere). When you load entities to cached list make sure that you turn off proxy creation (lazy loading and change tracking).

Caching per context instance really works but using context itself as a cache is pretty bad choice - in most scenarios I would call it EF anti-pattern. Use context as unit of work = do not reuse context for multiple logical operations.

Community
  • 1
  • 1
Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
1

you'll have to roll your own for any ef4 linq queries, as they are always resolved to sql, and thus will always hit the db. a simple cache for your couple tables probably wouldn't be hard to write.

if you're going to be querying by id though, you can use the ObjectContext.GetObjectByKey method, and it will look in the object cache before querying the db.

nathan gonzalez
  • 11,137
  • 4
  • 37
  • 57
  • Careful, "linq is always resolved to sql" is very untrue. LinqToObjects is one of several providers that has nothing to do with SQL or a database in general. – Ed Chapel Jun 21 '11 at 06:32
  • @Ed, i should qualify what kind of linq i'm talking about for a ef4 question? come on. its obviously going to resolve to sql. i'll amend the response though to not confuse people that don't read titles or tags. – nathan gonzalez Jun 21 '11 at 06:36
  • 2
    It depends. If the user includes a `ToArray()` or `ToList()` or otherwise forces the query to execute against the database, then subsequent expressions are frequently not LinqToEF. Your statement is too absolute with "always". – Ed Chapel Jun 21 '11 at 06:40
  • 1
    @ed, it is absolute. they aren't sometimes resolved to sql, they always are. if someone evaluates the query, they have to start a new one, and then its not the same query... this isn't really a debate here, its just simple facts. from http://msdn.microsoft.com/en-us/library/bb896241.aspx "When you query a conceptual model, the Entity Framework transforms the LINQ to Entities and Entity SQL query based on the conceptual model into an equivalent query against the data source." seems pretty absolute to me. – nathan gonzalez Jun 21 '11 at 06:52
  • I don't wanna get into a nerd purse fight, but... if you write some test code, instead of (mis)interpreting the documentation, you'll see no databases are harmed when querying a `List<>`. – Ed Chapel Jun 21 '11 at 15:33
  • 1
    @ed, i think you're missing the core point here. of course when you query a list it doesn't hit the database.there is no databse to hit. its when you query an object context. – nathan gonzalez Jun 21 '11 at 16:01
  • 1
    Fair enough. It appears as though we were speaking past one another. Should anyone read this far, do take Nathan's warning about avoiding the database. – Ed Chapel Jun 21 '11 at 16:25