c# - EF Creating business objects in Linq or in foreach -


i measuring differences in query execution , stumbled upon case have no explanation for. query should retrieve 10000 customers main address (a customer can have many addresses). used 2 different methods navigation properties differ in execution time.

the first method retrieves customers way write linq queries: write results directly business object , calling tolist(). method takes 25 seconds execute.

the second method retrieves customers list of ef entities first. ef entities converted business objects in foreach loop. method takes 2 seconds execute.

can explain difference? , possible modify first method execution time similar second?

private list<icustomer> navigationproperties_so(int method) {    using (entities context = new entities())    {       context.database.log = s => system.diagnostics.debug.writeline(s);        context.configuration.proxycreationenabled = false;       context.configuration.autodetectchangesenabled = false;        list<icustomer> customerlist = new list<icustomer>();       if (method == 1)       {          // execution time: 25 seconds          customerlist = (from c in context.cust                                            .include(o => o.addresslist)                                            .include(o => o.addresslist.select(p => p.addr))                              let mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault()                              select new customer                              {                                 cust = c,                                 mainaddress = mainaddress,                                 addr = mainaddress == null ? null : mainaddress.addr                              }).asnotracking().tolist<icustomer>();       }       else if (method == 2)       {          // execution time: 2 seconds          var templist = (from c in context.cust                                            .include(o => o.addresslist)                                            .include(o => o.addresslist.select(p => p.addr))                          select c).asnotracking().tolist();          foreach (var c in templist)          {             icustomer customer = new customer();             var mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault();             customer.cust = c;             customer.mainaddress = mainaddress;             customer.addr = mainaddress == null ? null : mainaddress.addr;             customerlist.add(customer);          }       }       return customerlist;    } } 

edit

here (simplified) queries generated entity framework:

method 1

select  *   [dba].[cust] [extent1] outer apply  (select top ( 1 )      *     [dba].[cust_addr] [extent2]     (([extent1].[id] = [extent2].[id]) , (n'1' = [extent2].[main_addr])     order 'a' ) [limit1] left outer join [dba].[addr] [extent3] on [limit1].[id] = [extent3].[id] 

method 2

select  * ( select      *      [dba].[cust] [extent1]     left outer join  (select *          [dba].[cust_addr] [extent2]         left outer join [dba].[addr] [extent3] on [extent2].[id] = [extent3].[id] ) [join1] on ([extent1].[id] = [join1].[id]) )  [project1] 

the difference first method filtering in query (´let´) while second method retrieves records , filters in loop.

i suspect

let mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault() 

is culprit. queries forces ef ask possible combinations returned. ef spends little time narrowing down scope before provides reasonable result set. can use sql server profiler @ queries generated.

in case, can use linq, rather foreach, @ end of second method (this won't performance, readability might improve):

return templist.select(c => new customer{cust=c, mainaddress = c.addresslist.firstordefault(o=>o.main_addr=="1"), ...); 

Comments