I am trying to set up some compiled queries in my project which uses a unit of work design pattern. These queries get reused multiple times during certain requests and making them compiled queries helps a lot in speeding up the application. One thing I noticed is that I have to pass in the datacontext that I am using instead of being able to use the repositories I have set up in my Unit of Work class.
Here is what works:
private static Func<PivotalDataContext, Binary, Binary, Int32?, IQueryable<Location>> GetLocationFunc
{
get
{
Func<PivotalDataContext, Binary, Binary, Int32?, IQueryable<Location>> func =
CompiledQuery.Compile(
(PivotalDataContext db, Binary destCityId, Binary stateId, Int32? cityNeoId) =>
(
(from cityDest in db.Destination_Cities
where
cityDest.Destination_City_Id == destCityId || cityDest.Neo_Id == cityNeoId
join destCountry in db.Destination_Countries
on cityDest.Destination_Country_Id equals destCountry.Destination_Country_Id into country
from destCountry in country.DefaultIfEmpty()
join destCont in db.Destination_Continents
on destCountry.Destination_Continent_Id equals destCont.Destination_Continent_Id into continent
from destCont in continent.DefaultIfEmpty()
select new Location
{
CityName = destCity.Name,
CountryName = destCountry.Name,
ContinentName = destContinent.Name
})));
return func;
}
}
Here is what I want:
Constructor:
private static IRepository<Destination_Country> _destCountryRepo;
private static IRepository<Destination_Continent> _destContinentRepo;
private static IRepository<Destination_City> _destinationCityRepo;
public LocationService()
{
_destCountryRepo = UnitOfWork.DestCountryRepo;
_destCityRepo = UnitOfWork.DestCityRepo;
_destContinentRepo = UnitOfWork.DestContinentRepo;
_destCountryRepo = UnitOfWork.DestCountryRepo;
}
Here is the compiled query (I have replaced the calls to the tables from the datacontext to the tables set up in the constructor):
private static Func<PivotalDataContext, Binary, Binary, Int32?, IQueryable<Location>> GetLocationFunc
{
get
{
Func<PivotalDataContext, Binary, Binary, Int32?, IQueryable<Location>> func =
CompiledQuery.Compile(
(PivotalDataContext db, Binary destCityId, Binary stateId, Int32? cityNeoId) =>
(
(from cityDest in _destCityRepo.Table
where
cityDest.Destination_City_Id == _destCityId || cityDest.Neo_Id == cityNeoId
join destCountry in _destCountryRepo.Table
on cityDest.Destination_Country_Id equals destCountry.Destination_Country_Id into country
from destCountry in country.DefaultIfEmpty()
join destCont in _destContinentRepo.Table
on destCountry.Destination_Continent_Id equals destCont.Destination_Continent_Id into continent
from destCont in continent.DefaultIfEmpty()
select new Location
{
CityName = destCity.Name,
CountryName = destCountry.Name,
ContinentName = destContinent.Name
})));
return func;
}
}
When I try using the tables set up in the UnitOfWork class and I create a breakpoint at the compiled query those tables are for some reason null, even though they are set when the class is created. Is it possible to do this? Or does the compiled query always need a datacontext passed in?
Thanks in advance!
Short answer: Yes, you must pass it in.
The way that your code is structured is that you are providing the DataContext
along with the other arguments to execute the query. Because you are hanging this off of a static property, you will always have to pass in the DataContext
because it is not static.
But even if you created the query in a non-static context, there isn't a proper circumstance where the DataContext
would be created and live as long as the query. You would end up with a long-lived DataContext
which is not how it is intended to be used and introduces a lot of problems.