Entity framework nested projections are slow - entity-framework
I'm running a query to fetch a users profile. The query get the users details, as well as all the reviews they have posted, as well as the comments in the reviews.
It may well be a case of I'm trying to get back too much, but as the api is getting called from mobile, I'd rather get as much as I can in one network call rather than making multiple network calls.
At the moment this is generating some really long sql, and takes around 25 seconds!
Any tips on how to improve it, or whether projections are even right way to do it
public UserVM GetUserInfo(string userId, string currentUserId)
{
var results =
from u in context.AspNetUsers
where u.Id == userId
select new UserVM
{
Name = u.UserName, Id = u.Id, ProfilePic = u.ProfilePicUrl, FollowerCount = u.Followers.Count, FollowingCount = u.Following.Count,
MemberSince = u.RegisteredDate,
RatingsCount = u.Ratings.Count(x => x.IsDeleted!=true),
FollowedByCurrentUser = currentUserId != null && u.Followers.Any(x => x.FollowedByUserId == currentUserId && x.UserId == userId),
reviews =
from r in u.Ratings
where r.IsDeleted != true
&& r.IsDraft != true
select new RatingVM()
{
ratingId = r.Id,
author_name = r.User.UserName,
userId = r.UserId,
profile_photo_url = r.User.ProfilePicUrl,
rating = r.RatingValue,
text = r.RatingComment,
created = r.Created,
likeCount = r.RatingLikes.Count(x => x.IsLiked && x.RatingId == r.Id),
likedByCurrentUser = currentUserId != null && r.RatingLikes.Any(x => x.IsLiked && x.RatingId == r.Id && x.UserId == currentUserId),
photos = from ri in r.RatingImages
select new PhotoVM { Id = ri.Id, width = 0, height = 0, photo_reference = ri.PhotoUrl, isMember = true, googlePlaceId = r.Place.GooglePlaceId, placeName = r.Place.Name },
comments = from c in r.Comments
where c.IsDeleted != true
select new CommentVM { commentId = c.Id, Created = c.Created, CommentText = c.CommentText, RatingId = r.Id , UserName = c.User.UserName, ProfilePicUrl = c.User.ProfilePicUrl, userId = c.UserId }
}
};
return results.FirstOrDefault();
}
SELECT
[Project17].[C1] AS [C1],
[Project17].[UserName] AS [UserName],
[Project17].[Id] AS [Id],
[Project17].[ProfilePicUrl] AS [ProfilePicUrl],
[Project17].[C32] AS [C2],
[Project17].[C33] AS [C3],
[Project17].[RegisteredDate] AS [RegisteredDate],
[Project17].[C34] AS [C4],
[Project17].[C2] AS [C5],
[Project17].[C31] AS [C6],
[Project17].[C4] AS [C7],
[Project17].[C5] AS [C8],
[Project17].[C6] AS [C9],
[Project17].[C7] AS [C10],
[Project17].[C8] AS [C11],
[Project17].[C9] AS [C12],
[Project17].[C10] AS [C13],
[Project17].[C11] AS [C14],
[Project17].[C12] AS [C15],
[Project17].[C13] AS [C16],
[Project17].[C14] AS [C17],
[Project17].[C3] AS [C18],
[Project17].[C15] AS [C19],
[Project17].[C16] AS [C20],
[Project17].[C17] AS [C21],
[Project17].[C18] AS [C22],
[Project17].[C19] AS [C23],
[Project17].[C20] AS [C24],
[Project17].[C21] AS [C25],
[Project17].[C22] AS [C26],
[Project17].[C23] AS [C27],
[Project17].[C24] AS [C28],
[Project17].[C25] AS [C29],
[Project17].[C26] AS [C30],
[Project17].[C27] AS [C31],
[Project17].[C28] AS [C32],
[Project17].[C29] AS [C33],
[Project17].[C30] AS [C34]
FROM ( SELECT
[Limit1].[Id] AS [Id],
[Limit1].[UserName] AS [UserName],
[Limit1].[ProfilePicUrl] AS [ProfilePicUrl],
[Limit1].[RegisteredDate] AS [RegisteredDate],
[Limit1].[C1] AS [C1],
[Limit1].[C2] AS [C2],
[UnionAll1].[C1] AS [C3],
[UnionAll1].[Id] AS [C4],
[UnionAll1].[Id1] AS [C5],
[UnionAll1].[C2] AS [C6],
[UnionAll1].[C3] AS [C7],
[UnionAll1].[UserId] AS [C8],
[UnionAll1].[C4] AS [C9],
[UnionAll1].[RatingValue] AS [C10],
[UnionAll1].[RatingComment] AS [C11],
[UnionAll1].[Created] AS [C12],
[UnionAll1].[C5] AS [C13],
[UnionAll1].[C6] AS [C14],
[UnionAll1].[Id2] AS [C15],
[UnionAll1].[Id3] AS [C16],
[UnionAll1].[C7] AS [C17],
[UnionAll1].[C8] AS [C18],
[UnionAll1].[PhotoUrl] AS [C19],
[UnionAll1].[C9] AS [C20],
[UnionAll1].[GooglePlaceId] AS [C21],
[UnionAll1].[Name] AS [C22],
[UnionAll1].[C10] AS [C23],
[UnionAll1].[C11] AS [C24],
[UnionAll1].[C12] AS [C25],
[UnionAll1].[C13] AS [C26],
[UnionAll1].[C14] AS [C27],
[UnionAll1].[C15] AS [C28],
[UnionAll1].[C16] AS [C29],
[UnionAll1].[C17] AS [C30],
CASE WHEN ([UnionAll1].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C31],
[Limit1].[C3] AS [C32],
[Limit1].[C4] AS [C33],
[Limit1].[C5] AS [C34]
FROM (SELECT TOP (1)
#p__linq__4 AS [p__linq__4],
#p__linq__5 AS [p__linq__5],
[Project3].[Id] AS [Id],
[Project3].[UserName] AS [UserName],
[Project3].[ProfilePicUrl] AS [ProfilePicUrl],
[Project3].[RegisteredDate] AS [RegisteredDate],
1 AS [C1],
CASE WHEN ((#p__linq__1 IS NOT NULL) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Followers] AS [Extent5]
WHERE ([Project3].[Id] = [Extent5].[UserId]) AND ([Extent5].[FollowedByUserId] = #p__linq__2) AND ([Extent5].[UserId] = #p__linq__3)
))) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C2],
[Project3].[C1] AS [C3],
[Project3].[C2] AS [C4],
[Project3].[C3] AS [C5]
FROM ( SELECT
[Project2].[Id] AS [Id],
[Project2].[UserName] AS [UserName],
[Project2].[ProfilePicUrl] AS [ProfilePicUrl],
[Project2].[RegisteredDate] AS [RegisteredDate],
[Project2].[C1] AS [C1],
[Project2].[C2] AS [C2],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Ratings] AS [Extent4]
WHERE ([Project2].[Id] = [Extent4].[UserId]) AND (1 <> [Extent4].[IsDeleted])) AS [C3]
FROM ( SELECT
[Project1].[Id] AS [Id],
[Project1].[UserName] AS [UserName],
[Project1].[ProfilePicUrl] AS [ProfilePicUrl],
[Project1].[RegisteredDate] AS [RegisteredDate],
[Project1].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Followers] AS [Extent3]
WHERE [Project1].[Id] = [Extent3].[FollowedByUserId]) AS [C2]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[UserName] AS [UserName],
[Extent1].[ProfilePicUrl] AS [ProfilePicUrl],
[Extent1].[RegisteredDate] AS [RegisteredDate],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Followers] AS [Extent2]
WHERE [Extent1].[Id] = [Extent2].[UserId]) AS [C1]
FROM [dbo].[AspNetUsers] AS [Extent1]
WHERE [Extent1].[Id] = #p__linq__0
) AS [Project1]
) AS [Project2]
) AS [Project3] ) AS [Limit1]
OUTER APPLY (SELECT
CASE WHEN ([Filter10].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
[Project9].[Id] AS [Id],
[Project9].[Id] AS [Id1],
[Project9].[C1] AS [C2],
[Project9].[C2] AS [C3],
[Project9].[UserId] AS [UserId],
[Project9].[C3] AS [C4],
[Project9].[RatingValue] AS [RatingValue],
[Project9].[RatingComment] AS [RatingComment],
[Project9].[Created] AS [Created],
[Project9].[C5] AS [C5],
[Project9].[C4] AS [C6],
[Filter10].[Id1] AS [Id2],
[Filter10].[Id1] AS [Id3],
CASE WHEN ([Filter10].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 0 END AS [C7],
CASE WHEN ([Filter10].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 0 END AS [C8],
[Filter10].[PhotoUrl] AS [PhotoUrl],
CASE WHEN ([Filter10].[Id1] IS NULL) THEN CAST(NULL AS bit) ELSE cast(1 as bit) END AS [C9],
[Filter10].[GooglePlaceId] AS [GooglePlaceId],
[Filter10].[Name] AS [Name],
CAST(NULL AS int) AS [C10],
CAST(NULL AS int) AS [C11],
CAST(NULL AS datetime2) AS [C12],
CAST(NULL AS varchar(1)) AS [C13],
CAST(NULL AS int) AS [C14],
CAST(NULL AS varchar(1)) AS [C15],
CAST(NULL AS varchar(1)) AS [C16],
CAST(NULL AS varchar(1)) AS [C17]
FROM (SELECT
[Project7].[Id] AS [Id],
[Project7].[RatingValue] AS [RatingValue],
[Project7].[RatingComment] AS [RatingComment],
[Project7].[Created] AS [Created],
[Project7].[PlaceId] AS [PlaceId],
[Project7].[UserId] AS [UserId],
[Limit1].[UserName] AS [C1],
N'' AS [C2],
[Limit1].[ProfilePicUrl] AS [C3],
CASE WHEN ((#p__linq__4 IS NOT NULL) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RatingLikes] AS [Extent8]
WHERE ([Project7].[Id] = [Extent8].[RatingId]) AND ([Extent8].[IsLiked] = 1) AND ([Extent8].[RatingId] = [Project7].[Id]) AND ([Extent8].[UserId] = #p__linq__5)
))) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C4],
[Project7].[C1] AS [C5]
FROM ( SELECT
[Project6].[Id] AS [Id],
[Project6].[RatingValue] AS [RatingValue],
[Project6].[RatingComment] AS [RatingComment],
[Project6].[Created] AS [Created],
[Project6].[PlaceId] AS [PlaceId],
[Project6].[UserId] AS [UserId],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[RatingLikes] AS [Extent7]
WHERE ([Project6].[Id] = [Extent7].[RatingId]) AND ([Extent7].[IsLiked] = 1) AND ([Extent7].[RatingId] = [Project6].[Id])) AS [C1]
FROM ( SELECT
[Extent6].[Id] AS [Id],
[Extent6].[RatingValue] AS [RatingValue],
[Extent6].[RatingComment] AS [RatingComment],
[Extent6].[Created] AS [Created],
[Extent6].[PlaceId] AS [PlaceId],
[Extent6].[UserId] AS [UserId]
FROM [dbo].[Ratings] AS [Extent6]
WHERE ([Limit1].[Id] = [Extent6].[UserId]) AND (1 <> [Extent6].[IsDeleted]) AND (1 <> [Extent6].[IsDraft])
) AS [Project6]
) AS [Project7] ) AS [Project9]
OUTER APPLY (SELECT [Extent9].[Id] AS [Id1], [Extent9].[PhotoUrl] AS [PhotoUrl], [Project10].[Name] AS [Name], [Project10].[GooglePlaceId] AS [GooglePlaceId]
FROM [dbo].[RatingImages] AS [Extent9]
LEFT OUTER JOIN (SELECT
[Extent10].[Id] AS [Id],
[Extent10].[Name] AS [Name],
[Extent10].[GooglePlaceId] AS [GooglePlaceId]
FROM [dbo].[Places] AS [Extent10]
WHERE [Project9].[PlaceId] = [Extent10].[Id] ) AS [Project10] ON 1 = 1
WHERE [Project9].[Id] = [Extent9].[RatingId] ) AS [Filter10]
UNION ALL
SELECT
2 AS [C1],
[Project15].[Id] AS [Id],
[Project15].[Id] AS [Id1],
[Project15].[C1] AS [C2],
[Project15].[C2] AS [C3],
[Project15].[UserId] AS [UserId],
[Project15].[C3] AS [C4],
[Project15].[RatingValue] AS [RatingValue],
[Project15].[RatingComment] AS [RatingComment],
[Project15].[Created] AS [Created],
[Project15].[C5] AS [C5],
[Project15].[C4] AS [C6],
CAST(NULL AS int) AS [C7],
CAST(NULL AS int) AS [C8],
CAST(NULL AS int) AS [C9],
CAST(NULL AS int) AS [C10],
CAST(NULL AS varchar(1)) AS [C11],
CAST(NULL AS bit) AS [C12],
CAST(NULL AS varchar(1)) AS [C13],
CAST(NULL AS varchar(1)) AS [C14],
[Join2].[Id2] AS [Id2],
[Join2].[Id2] AS [Id3],
[Join2].[Created] AS [Created1],
[Join2].[CommentText] AS [CommentText],
[Project15].[Id] AS [Id4],
[Join2].[UserName] AS [UserName],
[Join2].[ProfilePicUrl] AS [ProfilePicUrl],
[Join2].[UserId] AS [UserId1]
FROM (SELECT
[Project13].[Id] AS [Id],
[Project13].[RatingValue] AS [RatingValue],
[Project13].[RatingComment] AS [RatingComment],
[Project13].[Created] AS [Created],
[Project13].[UserId] AS [UserId],
[Limit1].[UserName] AS [C1],
N'' AS [C2],
[Limit1].[ProfilePicUrl] AS [C3],
CASE WHEN ((#p__linq__4 IS NOT NULL) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RatingLikes] AS [Extent13]
WHERE ([Project13].[Id] = [Extent13].[RatingId]) AND ([Extent13].[IsLiked] = 1) AND ([Extent13].[RatingId] = [Project13].[Id]) AND ([Extent13].[UserId] = #p__linq__5)
))) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C4],
[Project13].[C1] AS [C5]
FROM ( SELECT
[Project12].[Id] AS [Id],
[Project12].[RatingValue] AS [RatingValue],
[Project12].[RatingComment] AS [RatingComment],
[Project12].[Created] AS [Created],
[Project12].[UserId] AS [UserId],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[RatingLikes] AS [Extent12]
WHERE ([Project12].[Id] = [Extent12].[RatingId]) AND ([Extent12].[IsLiked] = 1) AND ([Extent12].[RatingId] = [Project12].[Id])) AS [C1]
FROM ( SELECT
[Extent11].[Id] AS [Id],
[Extent11].[RatingValue] AS [RatingValue],
[Extent11].[RatingComment] AS [RatingComment],
[Extent11].[Created] AS [Created],
[Extent11].[UserId] AS [UserId]
FROM [dbo].[Ratings] AS [Extent11]
WHERE ([Limit1].[Id] = [Extent11].[UserId]) AND (1 <> [Extent11].[IsDeleted]) AND (1 <> [Extent11].[IsDraft])
) AS [Project12]
) AS [Project13] ) AS [Project15]
INNER JOIN (SELECT [Extent14].[Id] AS [Id2], [Extent14].[CommentText] AS [CommentText], [Extent14].[Created] AS [Created], [Extent14].[RatingId] AS [RatingId], [Extent14].[IsDeleted] AS [IsDeleted], [Extent14].[UserId] AS [UserId], [Extent15].[UserName] AS [UserName], [Extent15].[ProfilePicUrl] AS [ProfilePicUrl]
FROM [dbo].[Comments] AS [Extent14]
INNER JOIN [dbo].[AspNetUsers] AS [Extent15] ON [Extent14].[UserId] = [Extent15].[Id] ) AS [Join2] ON ([Project15].[Id] = [Join2].[RatingId]) AND (1 <> [Join2].[IsDeleted])) AS [UnionAll1]
) AS [Project17]
ORDER BY [Project17].[Id] ASC, [Project17].[C31] ASC, [Project17].[C5] ASC, [Project17].[C3] ASC
EF6's loading strategy of using one big SQL query per LINQ query is not optimal for loading complex object graphs. There are several other ways to get your graph loaded.
For instance you could load the root AspNetUser entity, and then traverse the Navigation Properties to build your graph. EF would Lazy Load as needed. And once an entity is cached in the context, subsequent navigations would not cause additional queries.
In fact if you pre-fetch some or all of the related entities, EF will "stitch" or "fix-up" your navigation properties.
So as an optimization, you can write queries that fetch into the context cache the entities that you will need using a few simple and cheap queries.
something like
var user = context.AspNetUsers.Where(u => u.Id == userId).Single();
var followers = context.Followers.Where(f => f.UserId == userId).ToList();
var ratings = context.Ratings.Where(f => f.UserId == userId).ToList();
var ratingIds = ratings.Select(r => r.Id).ToList();
var ratingLikes = context.RatingLikes.Where(x => ratingIds.Contains(x.RatingId) && x.IsLiked ).ToList();
var ratingPhotos = context.RatingPhotos.Where(x => ratingIds.Contains(x.RatingId)).ToList();
Then build your results from the loaded AspNetUser, eg
var u = user;
var results =
select new UserVM
{
Name = u.UserName,
Id = u.Id,
ProfilePic = u.ProfilePicUrl,
FollowerCount = u.Followers.Count, . . .
Related
SELECT with CASE WHEN and value after THEN instead of String
My query is: SELECT id, CASE WHEN EXISTS( SELECT data_od FROM bp_stan_produkt WHERE id_produkt = bp_produkt.id AND data_do IS NULL AND id_stan_produkt = 313 ) THEN 'TAK' ELSE 'NIE' END AS "313" FROM bp_produkt WHERE id IN(21048528) Is it possible to put data_od to column 313 instead of TAK or do I have to create function, make SELECT data_od into some_variable and then some_variable?
Yes it is possible: select id, case when exists (select data_od from bp_stan_produkt where id_produkt = bp_produkt.id and data_do is null and id_stan_produkt = 313) then (select to_char(data_od, 'YYYY-MM-DD') from bp_stan_produkt where id_produkt = bp.id and data_do is null and id_stan_produkt = 313) else 'NIE' end as "313" from bp_produkt where id in(21048528); EDIT: SELECT bp.id, COALESCE(t.data_od_t, 'NIE') AS "313" FROM bp_produkt bp LEFT JOIN LATERAL (select to_char(data_od, 'YYYY-MM-DD') AS data_od_t from bp_stan_produkt where id_produkt = bp.id and data_do is null and id_stan_produkt = 313) t ON TRUE WHERE bp.id in(21048528)
EF on IDBcommandInterceptor and DBDataReader
I am trying to Mock EF on IDBcommandInterceptor For insert / update operations it is enough simple - I can return a DbDataReader made of a single field or an int However, for select operations, if there are some "include", then the shape of the sql result is pretty ... awesome How could I obtain from ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> the fields and the names and the corresponding entities for the DbDataReader result? Thank you, Example : Trying to read Department(Id, Name) from Id with include on Employee(Id, Name .IDDepartment, DateModification, DateCreation, User) The Command that obtains the DBDataReader for an include is below . I want to know the fields names (like C1, ID1, Name1 and others) to be capable of Mocking. SELECT [Project2].[Id] AS [Id], [Project2].[Name] AS [Name], [Project2].[C1] AS [C1], [Project2].[Id1] AS [Id1], [Project2].[Name1] AS [Name1], [Project2].[IDDepartment] AS [IDDepartment], [Project2].[DateModification] AS [DateModification], [Project2].[DateCreation] AS [DateCreation], [Project2].[User] AS [User], [Project2].[Archive] AS [Archive] FROM ( SELECT [Limit1].[Id] AS [Id], [Limit1].[Name] AS [Name], [Extent2].[Id] AS [Id1], [Extent2].[Name] AS [Name1], [Extent2].[IDDepartment] AS [IDDepartment], [Extent2].[DateModification] AS [DateModification], [Extent2].[DateCreation] AS [DateCreation], [Extent2].[User] AS [User], [Extent2].[Archive] AS [Archive], CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM (SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name] FROM [dbo].[Department] AS [Extent1] WHERE [Extent1].[Id] = #p__linq__0 ) AS [Limit1] LEFT OUTER JOIN [dbo].[Employee] AS [Extent2] ON [Limit1].[Id] = [Extent2].[IDDepartment] ) AS [Project2] ORDER BY [Project2].[Id] ASC, [Project2].[C1] ASC
You should be able to get the column names from the reader by doing something like this var columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList(); That in the case you only need the names. If you get the whole schema for the result table, you could get it by doing this: DataTable schemaTable = reader.GetSchemaTable(); And then iterate through the collection of rows in the datatable to get the properties of each column. Does that help to answer your question?
Query on query result
http://sqlfiddle.com/#!3/e4891/1 for the above resulting query(which pivots data) I want to run my one more select condition. For example select (C1 & C2) from ‘the above pivoted query results’ IS it possible to do it? CTE will help here? SQL Server 2008 and above.
Try this: WITH Data AS ( select * from ( select MemId, Condition_id, condition_result from t ) x pivot ( sum(condition_result) for condition_id in ([C1], [C2], [C3], [C4]) ) p ) SELECT C1, C2 FROM Data SQLFiddle: http://sqlfiddle.com/#!3/e4891/3
either change your select to only select the fields that you want: select [C1], [C2] from ( select MemId, Condition_id, condition_result from t ) x pivot ( sum(condition_result) for condition_id in ([C1], [C2], [C3], [C4]) ) p OR ;with cte as ( select * from ( select MemId, Condition_id, condition_result from t ) x pivot ( sum(condition_result) for condition_id in ([C1], [C2], [C3], [C4]) ) p ) select [C1], [C2] from cte
Entity Framework: Many-to-Many .Include() not working
I have the following table structure: That is, a Supplier has a many-to-many relationship with People (of Person). Supplier 1--* SupplierPerson *--1 Person A Person has a one-to-many relationship with EmaiLAddresses, TelephoneNumbers and WebResources. Person 1--* EmailAddress Person 1--* TelephoneNumber Person 1--* WebResource I've highlighted the navigation properties. Given the LINQ-to-Entities using .Include() to load the dependencies and shape the result-set: ObjectQuery<Supplier> supplierQuery=((SopEntities)Context).Suppliers .Include("People") .Include("People.TelephoneNumbers") .Include("People.EmailAddresses") .Include("People.WebResources"); #if TRACE Trace.WriteLine(string.Format("GetAll(): {0}", supplierQuery.ToTraceString())); #endif return supplierQuery; I get the insanely large and rather useless SQL: SELECT [Project5].[ID] AS [ID], [Project5].[Key] AS [Key], [Project5].[CompanyName] AS [CompanyName], [Project5].[AddressLine1] AS [AddressLine1], [Project5].[AddressLine2] AS [AddressLine2], [Project5].[TownCity] AS [TownCity], [Project5].[CountyState] AS [CountyState], [Project5].[Postcode] AS [Postcode], [Project5].[Country] AS [Country], [Project5].[C25] AS [C1], [Project5].[C2] AS [C2], [Project5].[C3] AS [C3], [Project5].[C4] AS [C4], [Project5].[C5] AS [C5], [Project5].[C6] AS [C6], [Project5].[C7] AS [C7], [Project5].[C8] AS [C8], [Project5].[C9] AS [C9], [Project5].[C10] AS [C10], [Project5].[C11] AS [C11], [Project5].[C1] AS [C12], [Project5].[C12] AS [C13], [Project5].[C13] AS [C14], [Project5].[C14] AS [C15], [Project5].[C15] AS [C16], [Project5].[C16] AS [C17], [Project5].[C17] AS [C18], [Project5].[C18] AS [C19], [Project5].[C19] AS [C20], [Project5].[C20] AS [C21], [Project5].[C21] AS [C22], [Project5].[C22] AS [C23], [Project5].[C23] AS [C24], [Project5].[C24] AS [C25] FROM ( SELECT [Extent1].[ID] AS [ID], [Extent1].[Key] AS [Key], [Extent1].[CompanyName] AS [CompanyName], [Extent1].[AddressLine1] AS [AddressLine1], [Extent1].[AddressLine2] AS [AddressLine2], [Extent1].[TownCity] AS [TownCity], [Extent1].[CountyState] AS [CountyState], [Extent1].[Postcode] AS [Postcode], [Extent1].[Country] AS [Country], [UnionAll2].[C1] AS [C1], [UnionAll2].[C2] AS [C2], [UnionAll2].[C3] AS [C3], [UnionAll2].[C4] AS [C4], [UnionAll2].[C5] AS [C5], [UnionAll2].[C6] AS [C6], [UnionAll2].[C7] AS [C7], [UnionAll2].[C8] AS [C8], [UnionAll2].[C9] AS [C9], [UnionAll2].[C10] AS [C10], [UnionAll2].[C11] AS [C11], [UnionAll2].[C12] AS [C12], [UnionAll2].[C13] AS [C13], [UnionAll2].[C14] AS [C14], [UnionAll2].[C15] AS [C15], [UnionAll2].[C16] AS [C16], [UnionAll2].[C17] AS [C17], [UnionAll2].[C18] AS [C18], [UnionAll2].[C19] AS [C19], [UnionAll2].[C20] AS [C20], [UnionAll2].[C21] AS [C21], [UnionAll2].[C22] AS [C22], [UnionAll2].[C23] AS [C23], [UnionAll2].[C24] AS [C24], CASE WHEN ([UnionAll2].[C2] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C25] FROM [dbo].[Supplier] AS [Extent1] OUTER APPLY (SELECT [UnionAll1].[C1] AS [C1], [UnionAll1].[PersonID] AS [C2], [UnionAll1].[SupplierID] AS [C3], [UnionAll1].[SupplierID1] AS [C4], [UnionAll1].[ID] AS [C5], [UnionAll1].[Title] AS [C6], [UnionAll1].[FirstName] AS [C7], [UnionAll1].[Initials] AS [C8], [UnionAll1].[LastName] AS [C9], [UnionAll1].[Position] AS [C10], [UnionAll1].[DepartmentID] AS [C11], [UnionAll1].[ID1] AS [C12], [UnionAll1].[Number] AS [C13], [UnionAll1].[Name] AS [C14], [UnionAll1].[PersonID1] AS [C15], [UnionAll1].[TelephoneNumberTypeID] AS [C16], [UnionAll1].[C2] AS [C17], [UnionAll1].[C3] AS [C18], [UnionAll1].[C4] AS [C19], [UnionAll1].[C5] AS [C20], [UnionAll1].[C6] AS [C21], [UnionAll1].[C7] AS [C22], [UnionAll1].[C8] AS [C23], [UnionAll1].[C9] AS [C24] FROM (SELECT CASE WHEN ([Extent4].[ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1], [Extent2].[PersonID] AS [PersonID], [Extent2].[SupplierID] AS [SupplierID], [Extent2].[SupplierID] AS [SupplierID1], [Extent3].[ID] AS [ID], [Extent3].[Title] AS [Title], [Extent3].[FirstName] AS [FirstName], [Extent3].[Initials] AS [Initials], [Extent3].[LastName] AS [LastName], [Extent3].[Position] AS [Position], [Extent3].[DepartmentID] AS [DepartmentID], [Extent4].[ID] AS [ID1], [Extent4].[Number] AS [Number], [Extent4].[Name] AS [Name], [Extent4].[PersonID] AS [PersonID1], [Extent4].[TelephoneNumberTypeID] AS [TelephoneNumberTypeID], CAST(NULL AS int) AS [C2], CAST(NULL AS varchar(1)) AS [C3], CAST(NULL AS varchar(1)) AS [C4], CAST(NULL AS int) AS [C5], CAST(NULL AS int) AS [C6], CAST(NULL AS varchar(1)) AS [C7], CAST(NULL AS varchar(1)) AS [C8], CAST(NULL AS int) AS [C9] FROM [dbo].[SupplierPerson] AS [Extent2] INNER JOIN [dbo].[Person] AS [Extent3] ON [Extent3].[ID] = [Extent2].[PersonID] LEFT OUTER JOIN [dbo].[TelephoneNumber] AS [Extent4] ON [Extent3].[ID] = [Extent4].[PersonID] WHERE [Extent1].[ID] = [Extent2].[SupplierID] UNION ALL SELECT 2 AS [C1], [Extent5].[PersonID] AS [PersonID], [Extent5].[SupplierID] AS [SupplierID], [Extent5].[SupplierID] AS [SupplierID1], [Extent6].[ID] AS [ID], [Extent6].[Title] AS [Title], [Extent6].[FirstName] AS [FirstName], [Extent6].[Initials] AS [Initials], [Extent6].[LastName] AS [LastName], [Extent6].[Position] AS [Position], [Extent6].[DepartmentID] AS [DepartmentID], CAST(NULL AS int) AS [C2], CAST(NULL AS varchar(1)) AS [C3], CAST(NULL AS varchar(1)) AS [C4], CAST(NULL AS int) AS [C5], CAST(NULL AS int) AS [C6], [Extent7].[ID] AS [ID1], [Extent7].[Email] AS [Email], [Extent7].[Name] AS [Name], [Extent7].[PersonID] AS [PersonID1], CAST(NULL AS int) AS [C7], CAST(NULL AS varchar(1)) AS [C8], CAST(NULL AS varchar(1)) AS [C9], CAST(NULL AS int) AS [C10] FROM [dbo].[SupplierPerson] AS [Extent5] INNER JOIN [dbo].[Person] AS [Extent6] ON [Extent6].[ID] = [Extent5].[PersonID] INNER JOIN [dbo].[EmailAddress] AS [Extent7] ON [Extent6].[ID] = [Extent7].[PersonID] WHERE [Extent1].[ID] = [Extent5].[SupplierID]) AS [UnionAll1] UNION ALL SELECT 3 AS [C1], [Extent8].[PersonID] AS [PersonID], [Extent8].[SupplierID] AS [SupplierID], [Extent8].[SupplierID] AS [SupplierID1], [Extent9].[ID] AS [ID], [Extent9].[Title] AS [Title], [Extent9].[FirstName] AS [FirstName], [Extent9].[Initials] AS [Initials], [Extent9].[LastName] AS [LastName], [Extent9].[Position] AS [Position], [Extent9].[DepartmentID] AS [DepartmentID], CAST(NULL AS int) AS [C2], CAST(NULL AS varchar(1)) AS [C3], CAST(NULL AS varchar(1)) AS [C4], CAST(NULL AS int) AS [C5], CAST(NULL AS int) AS [C6], CAST(NULL AS int) AS [C7], CAST(NULL AS varchar(1)) AS [C8], CAST(NULL AS varchar(1)) AS [C9], CAST(NULL AS int) AS [C10], [Extent10].[ID] AS [ID1], [Extent10].[Url] AS [Url], [Extent10].[Name] AS [Name], [Extent10].[PersonID] AS [PersonID1] FROM [dbo].[SupplierPerson] AS [Extent8] INNER JOIN [dbo].[Person] AS [Extent9] ON [Extent9].[ID] = [Extent8].[PersonID] INNER JOIN [dbo].[WebResource] AS [Extent10] ON [Extent9].[ID] = [Extent10].[PersonID] WHERE [Extent1].[ID] = [Extent8].[SupplierID]) AS [UnionAll2] ) AS [Project5] ORDER BY [Project5].[ID] ASC, [Project5].[C25] ASC, [Project5].[C2] ASC, [Project5].[C3] ASC, [Project5].[C5] ASC, [Project5].[C1] ASC Which populates the Supplier with People, but not the TelephoneNumbers, EmailAddresses or WebResources. When executed in SQL Management Studio, I get the incomplete record set: Clearly, the .Include() is not working due to my misunderstanding of its capabilities. I really would like to avoid having to call the People schema seperately. How can I have this generate useful SQL?
Telerik's RadGridView + WCF Data Services + Entity Framework = Terrible performance
We have a simple LOB application that: pulls data from EF serves data across the wire with WCF Data Services renders that data on Telerik's RadGridView This works really well in the default scenario as users are able to filter data by using the built-in Telerik filter control which presents all the options they want. The problem happens when re-constructing the query sent from WCF Data Services when the 'Contains' operator is used: WCF Data Services adds a bunch of "IIF" lambda expressions which, EF then expands into T-SQL CASE statements This takes a query that should look like: SELECT TOP (25) [Project1].[TaskID] AS [TaskID], [Project1].[ProductSubmissionID] AS [ProductSubmissionID], ... FROM ( SELECT [Extent1].[TaskID] AS [TaskID], [Extent1].[ProductSubmissionID] AS [ProductSubmissionID], ... FROM [dbo].[Task] AS [Extent1] LEFT OUTER JOIN [dbo].[OperationDataProduct] AS [Extent2] ON [Extent1].[ProductID] = [Extent2].[ProductID] LEFT OUTER JOIN [dbo].[vProductOwnership] AS [Extent3] ON [Extent1].[ProductID] = [Extent3].[ProductID] LEFT OUTER JOIN [dbo].[User] AS [Extent4] ON [Extent2].[ChannelManagerID] = [Extent4].[UserID] LEFT OUTER JOIN [dbo].[User] AS [Extent5] ON [Extent2].[ProductOwnerID] = [Extent5].[UserID] WHERE [Extent1].Type IN ('Content','Concept','Financial') AND [Extent1].MarketplaceName LIKE '%prod%' Into one that looks like this: SELECT TOP (25) [Project1].[TaskID] AS [TaskID], [Project1].[ProductSubmissionID] AS [ProductSubmissionID], ... FROM ( SELECT [Extent1].[TaskID] AS [TaskID], [Extent1].[ProductSubmissionID] AS [ProductSubmissionID], ... FROM [dbo].[Task] AS [Extent1] LEFT OUTER JOIN [dbo].[OperationDataProduct] AS [Extent2] ON [Extent1].[ProductID] = [Extent2].[ProductID] LEFT OUTER JOIN [dbo].[vProductOwnership] AS [Extent3] ON [Extent1].[ProductID] = [Extent3].[ProductID] LEFT OUTER JOIN [dbo].[User] AS [Extent4] ON [Extent2].[ChannelManagerID] = [Extent4].[UserID] LEFT OUTER JOIN [dbo].[User] AS [Extent5] ON [Extent2].[ProductOwnerID] = [Extent5].[UserID] WHERE (CASE WHEN (CASE WHEN (((CASE WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END IS NULL) THEN CAST(NULL AS bit) WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%') THEN cast(1 as bit) WHEN ( NOT (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%')) THEN cast(0 as bit) END) = 1) AND ([Extent1].[SubmissionOrTaskType] IN (N'Content',N'Concept',N'Financial'))) THEN cast(1 as bit) WHEN ( NOT (((CASE WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END IS NULL) THEN CAST(NULL AS bit) WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%') THEN cast(1 as bit) WHEN ( NOT (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%')) THEN cast(0 as bit) END) = 1) AND ([Extent1].[SubmissionOrTaskType] IN (N'Content',N'Concept',N'Financial')))) THEN cast(0 as bit) END IS NULL) THEN cast(0 as bit) WHEN (((CASE WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END IS NULL) THEN CAST(NULL AS bit) WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%') THEN cast(1 as bit) WHEN ( NOT (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%')) THEN cast(0 as bit) END) = 1) AND ([Extent1].[SubmissionOrTaskType] IN (N'Content',N'Concept',N'Financial'))) THEN cast(1 as bit) WHEN ( NOT (((CASE WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END IS NULL) THEN CAST(NULL AS bit) WHEN (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%') THEN cast(1 as bit) WHEN ( NOT (CASE WHEN ([Extent1].[MarketplaceName] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE LOWER([Extent1].[MarketplaceName]) END LIKE N'%prod%')) THEN cast(0 as bit) END) = 1) AND ([Extent1].[SubmissionOrTaskType] IN (N'Content',N'Concept',N'Financial')))) THEN cast(0 as bit) END) = 1 ) AS [Project1] ORDER BY [Project1].[TaskID] ASC My question is: has anyone bumped into this problem before and is there a low cost solution? I can see re-writing the EF QueryProvider to be a solution, but it's not exactly low cost. TIA
We wound up writing a QueryProvider to fix this issue. It wound up being lower cost than originally expected, but still adds quiet a bit of unnecessary complexity. The IQToolkit has some decent examples of how to begin this.