views:

350

answers:

2

I've come across what appears to be a bug in linq to sql where identity caching does not work when performing primary key queries inside of a compiled query.

I wrote the following sample to demonstrate the usage of identity caching. It only executes one call to the database the first time it's hit, every time after that it retrieves the customer entity from the data context's cache.

    for(int i=0; i<10; i++)
    {
        DataContext.GetTable<Customer>().Single(c=>c.Id == 1);
    }

Unfortunately, when I convert the above sample to a compiled query, it fails to utilize the identity cache and actually executes 10 calls to the database.

    for(int i=0; i<10; i++)
    {
        RetrieveCustomer(DataContext, 1);
    }

    private static readonly Func<DataContext, int, Customer> RetrieveCustomer =
    CompiledQuery.Compile((DataContext context, int id) => context.GetTable<Customer>().Single(c=>c.Id == id));

Has anyone else come across this problem and created a workaround for it? It is extremely important for server based applications to utilize compiled queries and identity caching, so I'm hoping this is a problem that someone else has worked through before!

+1  A: 

Looks like a bug - there have been a number in this area.

As a work-around I wouldn't create a compiled query for such a small/simple operation - the real benefit of compiled query is for large queries that take a lot of time to process into TSQL.

Update: This is a bug and was resolved as will not fix.

DamienG
It seems silly to make a big deal about compiling such a small query but our application is a server that accepts many client requests and has to make hundreds and even thousands of database retrievals per request, so every bit really matters.
Otter
In this case you might want to measure it - I'd be surprised if the overhead of parsing this query is any more efficient than the compiled query route.
DamienG
A: 

I ended up using a dirty hack to workaround this by using reflection to call a private method of linq entity objects called GetCachedEntity to forcefully utilize the cache. I didn't have time to implement a cleaner solution but for anyone interested in this topic I would recommend implementing your own caching mechanism for this scenario.

Otter