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,但在大多数情况下,我认为它会在中间解决我的问题。