【问题标题】:How to Eager Load associated data in EF Core?如何在 EF Core 中急切加载关联数据?
【发布时间】:2016-07-28 00:41:41
【问题描述】:

我有一个 Gig 模型如下:

public class Gig
{
    public int Id { get; set; }

    [Required]
    public ApplicationUser Artist { get; set; }

    [Required]
    public string ArtistId { get; set; }

    public DateTime DateTime { get; set; }

    [Required]
    [StringLength(255)]
    public string Venue { get; set; }

    [Required]
    public Genre Genre { get; set; }

    [Required]
    public byte GenreId { get; set; }
}

在 EF6 中,我能够使用以下代码急切加载 ArtistGenre

            var gigs = _context.Attendances
            .Where(a => a.AttendeeId == userId)
            .Select(a => a.Gig)
            .Include(a => a.Artist)
            .Include(a => a.Genre)
            .ToList();

但使用 EF Core,艺术家信息或流派信息不会被加载。 SQL Profiler 显示没有在投影表上调用 INNER JOIN。

SELECT [a.Gig].[Id], [a.Gig].[ArtistId], [a.Gig].[DateTime], [a.Gig].[GenreId], [a.Gig].[Venue]
FROM [Attendances] AS [a]
INNER JOIN [Gigs] AS [a.Gig] ON [a].[GigId] = [a.Gig].[Id]
WHERE [a].[AttendeeId] = @__userId_0',N'@__userId_0 nvarchar(450)',@__userId_0=N'469d8515-9a04-46af-9276-09c6fead9e10'

有人可以帮我重新编写 EF Core 的查询以包含投影表吗?

更新: 添加了指向数据库架构脚本here 的链接。在这里只发布演出表:

CREATE TABLE [dbo].[Gigs](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ArtistId] [nvarchar](450) NOT NULL,
    [DateTime] [datetime2](7) NOT NULL,
    [GenreId] [tinyint] NOT NULL,
    [Venue] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_Gigs] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[Attendances]  WITH CHECK ADD  CONSTRAINT [FK_Attendances_AspNetUsers_AttendeeId] FOREIGN KEY([AttendeeId])
REFERENCES [dbo].[AspNetUsers] ([Id])
GO
ALTER TABLE [dbo].[Attendances] CHECK CONSTRAINT [FK_Attendances_AspNetUsers_AttendeeId]
GO
ALTER TABLE [dbo].[Attendances]  WITH CHECK ADD  CONSTRAINT [FK_Attendances_Gigs_GigId] FOREIGN KEY([GigId])
REFERENCES [dbo].[Gigs] ([Id])
GO
ALTER TABLE [dbo].[Attendances] CHECK CONSTRAINT [FK_Attendances_Gigs_GigId]
GO
ALTER TABLE [dbo].[Gigs]  WITH CHECK ADD  CONSTRAINT [FK_Gigs_AspNetUsers_ArtistId] FOREIGN KEY([ArtistId])
REFERENCES [dbo].[AspNetUsers] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Gigs] CHECK CONSTRAINT [FK_Gigs_AspNetUsers_ArtistId]
GO
ALTER TABLE [dbo].[Gigs]  WITH CHECK ADD  CONSTRAINT [FK_Gigs_Genres_GenreId] FOREIGN KEY([GenreId])
REFERENCES [dbo].[Genres] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Gigs] CHECK CONSTRAINT [FK_Gigs_Genres_GenreId]
GO

【问题讨论】:

  • 能否请您提供 sql 脚本以针对此生成 DB 架构。
  • 您的表之间的外键是否创建正确? Gigs 表需要有 ApplicationUserGenre 表的外键。
  • 添加了脚本链接,并仅提供了原始问题的 Gigs 架构

标签: entity-framework asp.net-core entity-framework-core


【解决方案1】:

如果您打开 EF Core Logging,您将在日志中看到如下内容:

导航的包含操作:“a.Gig.Artist”被忽略,因为目标导航在最终查询结果中不可到达。

a.Gig.Genre 类似。

目前看来 EF Core 无法处理此类查询的包含(不从结果实体开始)。我可以提出的唯一解决方法是像这样重写查询:

var gigs = _context.Gigs
    .Where(g => g.Attendances.Any(a => a.AttendeeId == userId))
    .Include(g => g.Artist)
    .Include(g => g.Genre)
    .ToList();

或者这个(转化为更好的 SQL,尽管 SQL 执行计划可能相同):

var gigs = (from g in _context.Gigs
            from a in g.Attendances
            where a.AttendeeId == userId
            select g)
    .Include(g => g.Artist)
    .Include(g => g.Genre)
    .ToList();

【讨论】:

  • 上述建议都不起作用,因为我无法从 Gigs 参加出席。
  • 只需在Gig -> public ICollection<Attendance> Attendances { get; set; } 中创建Attendance.Gig 的反向导航属性。或使用手册joinwhere。对于第一个g => _context.Attendances.Any(a => a.GidId == g.Id && a.AttendeeId == userId)。第二:代替from a in g.Attendances 使用join a in _context.Attendances on g.Id equals a.GigId。但是导航属性更好。
  • 它不会更改您当前的数据库架构和/或 FK 关联。但可以让您轻松地从父级“导航”到子级,这对于轻松重写查询至关重要。
  • 我在我的 Gig 模型中添加了导航属性:ICollection Attendances,迁移创建了两个新键(GigId1 用于 FK,GigId2 用于索引)。仅执行代码而不进行任何其他更改并没有获得我之前获得的任何数据(即,在我获得没有相关 Aritst 和 Genre 的所有字段之前,现在我什么也没得到,因为我添加了这个 Nav 道具)
  • 这很奇怪,因为我在发布上述答案之前在我的 EF Core 测试环境中创建了这样的模型(唯一的区别是 ApplicationUser 属性不是必需的),它创建了正确的表/列/FK 和两种查询变体都有效(而原始查询变体没有)。您的模型中一定还有其他内容,您可以发布实际的实体类和配置(如果有的话)吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多