When Mapping an IQueryable I see the database getting hit twice in my profiler. Any way to avoid this?

1,099 views
Skip to first unread message

brooklynDev

unread,
Mar 30, 2011, 2:08:14 PM3/30/11
to AutoMapper-users
In a controller action I am getting an IQueryable back from my service
layer and passing it into my view, when the automapper filter maps the
IQueryable to my ViewModel the query gets executed against the db
server twice. If I call .ToList() beforehand and pass the resulting
list to the view the query is only executed once.

It's not the end of the world or anything but I'd prefer the
flexibility to not have to explicitly pull down my entities into a
List before AutoMapper does it's mapping. Is there anyway to avoid the
double database hit of passing an IQueryable to Mapper.Map()?

bd

Todd Behunin

unread,
Mar 30, 2011, 7:22:06 PM3/30/11
to AutoMapper-users
I was encountering a similar problem you are encountering and
documented it on SO:
http://stackoverflow.com/questions/2413365/linq-to-sql-db-object-to-domain-object-mapping-and-performance

The answer I got from that post was to "use Automapper" - which is how
I became familiar with it.

AutoMapper doesn't solve that problem - just makes the mapping easier.
So, ultimately how I solved it was instead of querying the tables
directly (via Linq to Sql), I instead queried VIEWS which I wrote in
the db. By querying views, I was receiving a FLAT, projected result
set that wasn't "linked" to other tables/views. That resulted in ONE
call being executed. The drawback is that you have to write a view and
do all your joins in there. The same could be said with stored
procedures- you can call views or sprocs and get a flat result set
back which you can then map to your domain or other object(s) without
worrying about multiple calls being made.

HTH

Todd

brooklynDev

unread,
Mar 30, 2011, 8:45:41 PM3/30/11
to AutoMapper-users
My issue is different than the one you are describing. I'm feeding a
single IQueryable DbSet into automapper, no projection at all just one
set of entities that EF gets from a table. I pass that into
Mapper.Map() via an action filter and two identical round trips are
made to the database before my ViewModel spits out. If I pass
explicitly call ToList(); in my controller before the action method is
called its only one.

On Mar 30, 7:22 pm, Todd Behunin <tbehu...@gmail.com> wrote:
> I was encountering a similar problem you are encountering and
> documented it on SO:http://stackoverflow.com/questions/2413365/linq-to-sql-db-object-to-d...

Todd Behunin

unread,
Mar 30, 2011, 11:35:13 PM3/30/11
to AutoMapper-users
I'm pretty sure my prior issue and your issue are one-in-the-same.
Ultimately, you're not going to be able to have AutoMapper perform any
mapping till it has a result set pulled down, i.e. .ToList() was
triggered. I've tried multiple times and failed. This article might be
helpful to read too:

http://stackoverflow.com/questions/2212126/does-automapper-support-linq

var query = dbContext.Where(x => x.SomeProperty.Equals(123)).Select(x
=> x);
// possibly do more filtering here..
if (someCondition) {
query = query.Where(x => x.SomeOtherProperty.Equals(456)).Select(x
=> x);
}
Mapper.Map<IQueryable<SomeEntity>,
IList<DestinationEntity>>(query.ToList());

Is there a reason why you can't call .ToList() beforehand anyway? Is
it because you want lazy/deferred loading?

Todd

brooklynDev

unread,
Mar 31, 2011, 3:08:52 PM3/31/11
to AutoMapper-users
My issue doesn't have anything to do with when I expect deferred
execution to happen or the way I'm composing my queries or when I
expect the mapping to happen. It's simply that I'm seeing my
IQueryable, when passed to Automapper, is getting called twice, both
times identical executions (one of the two being superfluous). My
issue is about this duplicate, in my case unnecessary, database round
trip, nothing more, nothing less.

Again this isn't a showstopper or anything, I was just wondering if
there was someone out there who knew why this was or how to avoid it.
It would be convenient for me to pass IQueryables into AutoMapper but
only if AutoMapper will execute them against their store once and only
once.

Jimmy Bogard

unread,
Mar 31, 2011, 9:27:41 PM3/31/11
to automapp...@googlegroups.com
I have a pull request to fix this issue, but the problem was the pull request broke a lot of tests. It iterates the collection twice to first get a count of the # of elements to initialize the destination collection. We did this because we were seeing issues with large collections.

My suggestion - call ToList() or ToArray() before you pass it in. If you pass IQueryables to methods that expect IEnumerables, you can't assume that the sequences will always only be iterated once.

Thanks,

Jimmy

--
You received this message because you are subscribed to the Google Groups "AutoMapper-users" group.
To post to this group, send email to automapp...@googlegroups.com.
To unsubscribe from this group, send email to automapper-use...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/automapper-users?hl=en.


brooklynDev

unread,
Apr 1, 2011, 10:33:39 AM4/1/11
to AutoMapper-users
Understood. Thank you sir.

Jimmy Bogard

unread,
Apr 15, 2011, 6:46:26 PM4/15/11
to automapp...@googlegroups.com
Pull request applied! Try the 2.0.0.212 version in the teamcity.codebetter.com site.

Thanks,
Reply all
Reply to author
Forward
0 new messages