Reputation: 9780
A simple query for Groups
results in another query for every of its results:
using (var db = new DataClasses1DataContext())
{
db.Log = Console.Out;
var query = from g in db.Groups
let stats = from s in g.GroupCountryStats
select new
{
s.CountryId,
s.MembersCount
}
select new
{
g.ObjectId,
g.Name,
Stats = stats.ToArray()
};
var single = query.First(); // Take(2) would result in 2 extra calls, 3 in 3 and so on...
}
Console output (the Linq-to-Sql provider log):
SELECT TOP (1) [t0].[ObjectId] AS [ObjectId], [t0].[Name]
FROM [dbo].[Groups] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.7.3056.0
SELECT [t0].[CountryId] AS [CountryId], [t0].[MembersCount]
FROM [dbo].[GroupCountryStats] AS [t0]
WHERE [t0].[GroupId] = @x1
-- @x1: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.7.3056.0
Press any key to continue . . .
I would like to retrieve all the data in one query, instead of N+1 queries.
I tried using DataLoadOptions
, with LoadWith<Group>(T=>T.GroupCountryStats)
but the result is unchanged. The Linq2Sql still makes more than 1 call to the database.
How to avoid that and receive everything I need in a single call?
Upvotes: 0
Views: 284
Reputation: 109119
This is a bug (or a shortcoming at best) in LINQ-to-SQL. The query without First
or Take
translates into one decent SQL query containing an OUTER JOIN
. But of course it'll give you all groups.
When LINQ-to-SQL is faced with statements that limit the number of results it seems to be programmed to apply these to the root entity only and then to query the adhering entities separately.
The funny thing is: this doesn't happen when Skip
and Take
are combined. So, as a hack, you could use Skip(0).take(x)
, for example:
var results = query.Skip(0).Take(3).ToList();
If you need one result you have to do:
var results = query.Skip(0).Take(1).AsEnumerable().First();
Without .AsEnumerable()
will again relapse into 1 + 1 queries. (I assume the SQL translation of First
takes precedence in the query shape).
It's a dirty hack that's necessary to fight leaky abstractions of IQueryable
. Make sure that, if you choose to use it, you comment it well in the code.
A final comment: maybe you should consider turning to a more advanced ORM like Entity Framework.
Upvotes: 1