EF Linq query with conditional include

我的梦境 提交于 2019-12-23 03:29:35

问题


So I have the following Linq query:

var member = (from mem in 
              context.Members.Include(m => 
              m.MemberProjects.Select(mp => mp.Project))
              where mem.MemberId == memberId
             select mem).FirstOrDefault();

This returns a Member entity, with a set of MemberProjects that have a Project child. I would like to limit the MemberProjects to only those for which the Project child has a property ProjectIdParent == null.

One of my failed attempts might make the intent clearer:

var member = (from mem in context.Members
             .Include(m => m.MemberProjects
                            .Where(mp => 
                                   mp.Project.ProjectIdParent == null)
             .Select(proj => proj.Project))
             where mem.MemberId == memberId
             select mem).FirstOrDefault();

This of course complains of an invalid Include expression because of the Where clause.

Any thoughts on how to do this would be great :)


回答1:


DISCLAIMER: I havent tested this. This is just an idea. If you let me know the results, I will update this accordingly. (Skip to the update part for the tested solutions)

var member = (from mps in context.MemberProjects
                                .Include(m => m.Members)
                                .Include(m => m.Projects)  
              where mps.Project.ProjectIdParent == null
              select mps)
              .FirstOrDefault(mprojs => mprojs.Member.MemberId == memberId);     

I'd also analyze the queries using something like EFProfiler to make sure the generated queries dont leave the realm of sanity.

You can also take a look at this post by Jimmy Bogard on Many to Many relationships with ORMs.

Update

I came up with multiple tested solutions for this with EF 6.1.3. My Edmx looked like below:

The setup data is like below:

I was able to run code below to get the MemberFive correctly

var member = context.Members.FirstOrDefault
                     (m => m.MemberId == memberId 
                         && m.Projects.Any(p => p.ProjectParentId == null));

The generated SQL looked like this:

SELECT TOP (1) [Extent1].[MemberId]   AS [MemberId],
           [Extent1].[MemberName] AS [MemberName]
FROM   [dbo].[Members] AS [Extent1]
WHERE  ([Extent1].[MemberId] = 1)
   AND (EXISTS (SELECT 1 AS [C1]
                FROM   (SELECT [MemberProjects].[MemberId]  AS [MemberId],
                               [MemberProjects].[ProjectId] AS [ProjectId]
                        FROM   [dbo].[MemberProjects] AS [MemberProjects])     
           AS [Extent2]
                       INNER JOIN [dbo].[Projects] AS [Extent3]
                         ON [Extent3].[ProjectId] = [Extent2].[ProjectId]
                WHERE  ([Extent1].[MemberId] = [Extent2].[MemberId])
                       AND ([Extent3].[ProjectParentId] IS NULL)))

If you dont like the generated query you can use this:

 var memberQuery = @"Select M.* from Members M
                            inner join MemberProjects MP on M.MemberId = Mp.ProjectId
                            inner join Projects P on MP.ProjectId = P.ProjectId
                            where M.MemberId = @MemberId and P.ProjectParentId is NULL";
 var memberParams = new[]
                     {
                      new SqlParameter("@MemberId", 1)
                     };
 var member3 = context.Members.SqlQuery(memberQuery, memberParams)
               .FirstOrDefault();

The later consistently returned under 20ms vs the other one hovered around 60ms (if that matters to you).

I hope this helps.



来源:https://stackoverflow.com/questions/29382440/ef-linq-query-with-conditional-include

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!