yowslymie
yowslymie

Reputation: 31

Entity Framework: When will a variable be evaluated

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

Answers (1)

TomTom
TomTom

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

Related Questions