Reputation: 31
I encountered strange behaviour with EF and IQueryable.
public IQueryable<foo> getFoo()
{
IQueryable<foo> query;
string someVar = functies.getSomeInt().ToString();
try
{
query = from sTable in db.someTable
from oTable in db.otherTable
where sTable.Id == oTable.Id
&& sTable.Var == someVar
select sTable;
} catch {}
return query;
}
public Test()
{
var queryFoo = getFoo();
foreach(var foo in queryFoo)
{
//This works fine
}
}
Above example will run just fine, but when you put the declaration of someVar inside the try block, EF cannot seem to compare sTable.Var with someVar.
public IQueryable<foo> getFoo()
{
IQueryable<foo> query;
try
{
string someVar = functies.getSomeInt().ToString();
query = from sTable in db.someTable
from oTable in db.otherTable
where sTable.Id == oTable.Id
&& sTable.Var == someVar
select sTable;
} catch {}
return query;
}
public Test()
{
var queryFoo = getFoo();
foreach(var foo in queryFoo)
{
//This doesn't work
//unable to create constant value of type 'foo'
}
}
This results in an "Unable to create a constant value of type 'foo'. Only primitive types or enumeration types are supported in this context."
Is there any logical explanation to why EF is behaving this way? I really don't understand the difference, it probably has something to do with the scope of the variable. But it still seems strange.
What research gotten me so far (so if I follow below examples, someVar isn't local when nested further down???):
Local variables, such as the orderID variable in the following example, are evaluated on the client.
int orderID = 51987;
IQueryable<SalesOrderHeader> salesInfo =
from s in context.SalesOrderHeaders
where s.SalesOrderID == orderID
select s;
Also
Method parameters are also evaluated on the client. The orderID parameter passed into the MethodParameterExample method.
public static void MethodParameterExample(int orderID)
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
IQueryable<SalesOrderHeader> salesInfo =
from s in context.SalesOrderHeaders
where s.SalesOrderID == orderID
select s;
foreach (SalesOrderHeader sale in salesInfo)
{
Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue);
}
}
}
Literals and Parametesr on the Client
Not altered:
public IQueryable<klassen> getKlassenPerGebruiker(Db.Models.gebruiker gbr)
{
// Connectie met de database maken.
var db = new Datastore.Db.Models.dataContext(); //of type DbContext
IQueryable<klassen> query;
try
{
string jaar = functies.getHuidigStartJaar().ToString();
query = from klas in db.klassens
from kpg in db.klassenpergebruikers
from sj in db.schooljaars
where kpg.Klassen_id == klas.Id
&& kpg.Gebruikers_id == gbr.Id
&& sj.Id == klas.Schooljaar_id
&& sj.Start == jaar
&& kpg.School_id == gbr.School_id
orderby klas.Naam
select klas;
}
catch
{
query = null;
}
}
calling function;
IQueryable qklassen = gs.getKlassenPerGebruiker((user) Session["user"]);
if (qklassen != null)
{
foreach (klassen klas in qklassen)
{
}
}
Upvotes: 0
Views: 388
Reputation: 62093
It is evaluated when you evaluate it. Which happens when you materialize the query (ToArray,FirstOrDefault etc.). You return the query - and here is the problem.
Upvotes: 1