entity framework - What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()? -
i know differences of linq entities , linq objects first implements iqueryable
, second implements ienumerable
, question scope within ef 5.
my question what's technical difference(s) of 3 methods? see in many situations of them work. see using combinations of them .tolist().asqueryable()
.
what methods mean, exactly?
is there performance issue or lead use of 1 on other?
why 1 use, example,
.tolist().asqueryable()
instead of.asqueryable()
?
there lot this. let me focus on asenumerable
, asqueryable
, mention tolist()
along way.
what these methods do?
asenumerable
, asqueryable
cast or convert ienumerable
or iqueryable
, respectively. cast or convert reason:
when source object implements target interface, source object returned cast target interface. in other words: type not changed, compile-time type is.
when source object not implement target interface, source object converted object implements target interface. both type , compile-time type changed.
let me show examples. i've got little method reports compile-time type , actual type of object (courtesy jon skeet):
void reporttypeproperties<t>(t obj) { console.writeline("compile-time type: {0}", typeof(t).name); console.writeline("actual type: {0}", obj.gettype().name); }
let's try arbitrary linq-to-sql table<t>
, implements iqueryable
:
reporttypeproperties(context.observations); reporttypeproperties(context.observations.asenumerable()); reporttypeproperties(context.observations.asqueryable());
the result:
compile-time type: table`1 actual type: table`1 compile-time type: ienumerable`1 actual type: table`1 compile-time type: iqueryable`1 actual type: table`1
you see table class returned, representation changes.
now object implements ienumerable
, not iqueryable
:
var ints = new[] { 1, 2 }; reporttypeproperties(ints); reporttypeproperties(ints.asenumerable()); reporttypeproperties(ints.asqueryable());
the results:
compile-time type: int32[] actual type: int32[] compile-time type: ienumerable`1 actual type: int32[] compile-time type: iqueryable`1 actual type: enumerablequery`1
there is. asqueryable()
has converted array enumerablequery
, "represents ienumerable<t>
collection iqueryable<t>
data source." (msdn).
what's use?
asenumerable
used switch iqueryable
implementation linq objects (l2o), because former not support functions l2o has. more details see what effect of asenumerable() on linq entity?.
for example, in entity framework query can use restricted number of methods. if, example, need use 1 of our own methods in query typically write like
var query = context.observations.select(o => o.id) .asenumerable().select(x => mysupersmartmethod(x))
tolist
– converts ienumerable<t>
list<t>
– used purpose well. advantage of using asenumerable
vs. tolist
asenumerable
not execute query. asenumerable
preserves deferred execution , not build useless intermediate list.
on other hand, when forced execution of linq query desired, tolist
can way that.
asqueryable
can used make enumerable collection accept expressions in linq statements. see here more details: do need use asqueryable() on collection?.
note on substance abuse!
asenumerable
works drug. it's quick fix, @ cost , doesn't address underlying problem.
in many stack overflow answers, see people applying asenumerable
fix problem unsupported methods in linq expressions. price isn't clear. instance, if this:
context.mylongwidetable // table many records , columns .where(x => x.type == "type") .select(x => new { x.name, x.createdate })
...everything neatly translated sql statement filters (where
) , projects (select
). is, both length , width, respectively, of sql result set reduced.
now suppose users want see date part of createdate
. in entity framework you'll discover that...
.select(x => new { x.name, x.createdate.date })
...is not supported (at time of writing). ah, fortunately there's asenumerable
fix:
context.mylongwidetable.asenumerable() .where(x => x.type == "type") .select(x => new { x.name, x.createdate.date })
sure, runs, probably. pulls entire table memory , applies filter , projections. well, people smart enough where
first:
context.mylongwidetable .where(x => x.type == "type").asenumerable() .select(x => new { x.name, x.createdate.date })
but still columns fetched first , projection done in memory.
the real fix is:
context.mylongwidetable .where(x => x.type == "type") .select(x => new { x.name, dbfunctions.truncatetime(x.createdate) })
(but requires little bit more knowledge...)
what these methods not do?
now important caveat. when do
context.observations.asenumerable() .asqueryable()
you end source object represented iqueryable
. (because both methods cast , don't convert).
but when do
context.observations.asenumerable().select(x => x) .asqueryable()
what result be?
the select
produces whereselectenumerableiterator
. internal .net class implements ienumerable
, not iqueryable
. conversion type has taken place , subsequent asqueryable
can never return original source anymore.
the implication of using asqueryable
not way magically inject query provider specific features enumerable. suppose do
var query = context.observations.select(o => o.id) .asenumerable().select(x => x.tostring()) .asqueryable() .where(...)
the condition never translated sql. asenumerable()
followed linq statements definitively cuts connection entity framework query provider.
i deliberately show example because i've seen questions here people instance try 'inject' include
capabilities collection calling asqueryable
. compiles , runs, nothing because underlying object not have include
implementation anymore.
specific implementations
so far, queryable.asqueryable
, enumerable.asenumerable
extension methods. of course can write instance methods or extension methods same names (and functions).
in fact, common example of specific asenumerable
extension method datatableextensions.asenumerable
. datatable
not implement iqueryable
or ienumerable
, regular extension methods don't apply.
Comments
Post a Comment