C# 能否在实体框架导航属性上使用投影?

C# 能否在实体框架导航属性上使用投影?,c#,entity-framework,C#,Entity Framework,这是一个我无法回答的问题。我目前有以下简单的代码片段 return _context.UserProfiles .Single(p => p.ID == userID) .Organisations .Select(p => new { ID = p.ID }) .First() .ID; 这

这是一个我无法回答的问题。我目前有以下简单的代码片段

return _context.UserProfiles
                .Single(p => p.ID == userID)
                    .Organisations
                    .Select(p => new { ID = p.ID })
                    .First()
                    .ID;
这只是获取第一个用户配置文件(从UserProfiles WHERE…)中提取SELECT*,这很好。问题在于组织导航属性

我在迁移中首先使用代码,因此UesrProfiles和组织(多对多)之间有一个连接表,由EF自动创建。我最终得到了组织的userprofile导航属性和成员的组织导航属性。所以,简单

我对组织导航属性的问题是它不是投影的。在select和first上,我将以下SQL发送到DB服务器

SELECT 
    [Extent2].[ID] AS [ID], 
    [Extent2].[Description] AS [Description], 
    [Extent2].[ShortDescription] AS [ShortDescription], 
    [Extent2].[Name] AS [Name], 
    [Extent2].[Address] AS [Address], 
    [Extent2].[City] AS [City], 
    [Extent2].[State] AS [State], 
    [Extent2].[PostCode] AS [PostCode], 
    [Extent2].[Country] AS [Country], 
    [Extent2].[Created] AS [Created], 
    [Extent2].[CreatedBy] AS [CreatedBy]
    FROM  [dbo].[OrganisationMembers] AS [Extent1]
    INNER JOIN [dbo].[Organisations] AS [Extent2] ON [Extent1].[Organisation_ID] = [Extent2].[ID]
    WHERE [Extent1].[UserProfile_ID] = @EntityKeyValue1
既然我只投射ID,我不应该得到以下信息吗

SELECT 
    [Extent2].[ID] AS [ID]
    FROM  [dbo].[OrganisationMembers] AS [Extent1]
    INNER JOIN [dbo].[Organisations] AS [Extent2] ON [Extent1].[Organisation_ID] = [Extent2].[ID]
    WHERE [Extent1].[UserProfile_ID] = @EntityKeyValue1
连接如我所料是正确的,但不是柱。我想我可以为连接表创建另一个对象,然后手动编写代码连接和选择,但这是我希望EF能为我做的事情

更新

我不是在玩弄从First()带回的原始用户配置文件的排序和投影。如果我将代码更改为:

return _context.UserProfiles
   .Select(p => new { ID = p.ID, Organisations = p.Organisations.Select(q => new { ID = q.ID }) })
   .Single(p => p.ID == userID)
   .Organisations
   .First()
   .ID;
我最终得到了这个怪物:

SELECT 
    [Project1].[ID] AS [ID], 
    [Project1].[C1] AS [C1], 
    [Project1].[Organisation_ID] AS [Organisation_ID]
    FROM ( SELECT 
        [Limit1].[ID] AS [ID], 
        [Extent2].[Organisation_ID] AS [Organisation_ID], 
        CASE WHEN ([Extent2].[Organisation_ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
        FROM   (SELECT TOP (2) [Extent1].[ID] AS [ID]
            FROM [dbo].[UserProfiles] AS [Extent1]
            WHERE [Extent1].[ID] = @p__linq__0 ) AS [Limit1]
        LEFT OUTER JOIN [dbo].[OrganisationMembers] AS [Extent2] ON [Limit1].[ID] = [Extent2].[UserProfile_ID]
    )  AS [Project1]
    ORDER BY [Project1].[ID] ASC, [Project1].[C1] ASC
但是,我想这是我想要的

更新2

根据Gongdo的回答,我更新了以下内容:

    return _context.UserProfiles
                    .Where(p => p.ID == userID)
                    .Take(1)
                    .SelectMany(p => p.Organisations)
                    .Select(p => new { ID = p.ID })
                    .First().ID;
哪些产出:

SELECT 
    [Limit2].[Organisation_ID] AS [Organisation_ID]
    FROM ( SELECT TOP (1) 
        [Extent2].[Organisation_ID] AS [Organisation_ID]
        FROM   (SELECT TOP (1) [Extent1].[ID] AS [ID]
            FROM [dbo].[UserProfiles] AS [Extent1]
            WHERE [Extent1].[ID] = @p__linq__0 ) AS [Limit1]
        INNER JOIN [dbo].[OrganisationMembers] AS [Extent2] ON [Limit1].[ID] = [Extent2].[UserProfile_ID]
    )  AS [Limit2]

我更接近我想要的输出。非常感谢。

Single
SingleOrDefault
First
FirstOrDefault
本身就是投影方法。因此,您需要保持IQueryable,直到您实际需要投影它为止。你想怎么做就怎么做

return _context.UserProfiles
                .Where(p => p.ID == userID)
                .SelectMany(p => p.Organisations)
                .Select(p => new { ID = p.ID })
                .First()
                .ID;

谢谢你的回答。输出并不是我所期望的,但它可能比我使用一些内部联接在SQL中编写的要好。非常感谢没错,你想要一个用户配置文件。在
Where
之后使用
Take(1)
。这能解决你的问题吗?我希望如此。如果使用take(1),它实际上会执行多个子查询,并带有一个内部联接。我已经用查询和输出更新了问题。这有很大帮助,我明天会在工作中检查更复杂的iQueryTables,但在大多数情况下,我认为它会在中间解决我的问题。