当前位置: 首页 > 知识库问答 >
问题:

实体框架核心在转换时是延迟加载的

戎泰
2023-03-14

当将实体模型转换为DTO时,我对Entity Framework Core(v2.0.1)有一个问题。基本上,通过该短语的任何其他版本,当我不想加载时,它是延迟加载的。这是一个简单的。NET Core Console应用程序(带有Microsoft. EntityFrameworkCore. SqlServer(2.0.1)包)。

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

namespace EfCoreIssue
{
    class Program
    {
        static void Main(string[] args)
        {
            var dbOptions = new DbContextOptionsBuilder<ReportDbContext>()
                .UseSqlServer("Server=.;Database=EfCoreIssue;Trusted_Connection=True;")
                .Options;

            // Create and seed database if it doesn't already exist.
            using (var dbContext = new ReportDbContext(dbOptions))
            {
                if (dbContext.Database.EnsureCreated())
                {
                    string alphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

                    foreach (char alpha in alphas)
                    {
                        var report = new Report { Title = $"Report { alpha }" };

                        for (int tagId = 0; tagId < 10; tagId++)
                            report.Tags.Add(new ReportTag { TagId = tagId });

                        dbContext.Reports.Add(report);
                        dbContext.SaveChanges();
                    }
                }
            }

            using (var dbContext = new ReportDbContext(dbOptions))
            {
                var reports = dbContext.Reports
                    .Select(r => new ReportDto
                    {
                        Id = r.Id,
                        Title = r.Title,
                        Tags = r.Tags.Select(rt => rt.TagId)
                    })
                    .ToList();
            }
        }
    }

    class ReportDbContext : DbContext
    {
        public DbSet<Report> Reports { get; set; }

        public ReportDbContext(DbContextOptions<ReportDbContext> options)
            : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ReportTag>().HasKey(rt => new { rt.ReportId, rt.TagId });
        }
    }

    [Table("Report")]
    class Report
    {
        [Key]
        public int Id { get; set; }
        public string Title { get; set; }
        public virtual ICollection<ReportTag> Tags { get; set; }

        public Report()
        {
            Tags = new HashSet<ReportTag>();
        }
    }

    [Table("ReportTag")]
    class ReportTag
    {
        public int ReportId { get; set; }
        public int TagId { get; set; }
    }

    class ReportDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public IEnumerable<int> Tags { get; set; }
    }
}

现在,当执行ToList()方法来检索数据时,它正在执行以下SQL

SELECT [r].[Id], [r].[Title]
FROM [Report] AS [r]

如您所见,它没有努力加入[ReportTag]表,如果您实际尝试读取ReportDto上的Tags属性的值,那么它会触发另一个SQL查询

SELECT [rt].[TagId]
FROM [ReportTag] AS [rt]
WHERE @_outer_Id = [rt].[ReportId]

现在我知道EF Core不支持延迟加载,但在我看来这很像延迟加载。在这种情况下,我不希望它延迟加载。我试着改变var reports=dbContext。报告至var Reports=dbContext。报告。包括(r=

我甚至试着改变标签=r.Tags。选择(rt=

最后,在绝望中,我尝试更改var reports=dbContext。报告至var Reports=dbContext。报告。包括(r=

有没有人知道我可以做什么,这样它就可以加载到ReportDto了。标签属性?

共有1个答案

邢臻
2023-03-14

正如您所注意到的,当前包含集合投影的EF核心投影查询存在两个问题—(1)它们导致每个集合执行N个查询;(2)它们执行缓慢。

问题(2)很奇怪,因为具有讽刺意味的是EF Core不支持延迟加载相关的实体数据,而这种行为有效地将其用于投影。至少可以通过使用ToList()或类似工具强制立即执行。

问题(1)目前无法解决。它通过查询进行跟踪:优化投影相关集合的查询,使其不会产生N 1数据库查询#9282,并根据路线图(减少N 1查询项)最终将在下一个EF Core 2.1版本中修复(改进)。

我能想到的唯一解决方法是(以更高的数据传输和内存使用为代价)使用即时加载,然后进行投影(在LINQ到实体的上下文中):

var reports = dbContext.Reports
    .Include(r => r.Tags) // <-- eager load
    .AsEnumerable() // <-- force the execution of the LINQ to Entities query
    .Select(r => new ReportDto
    {
        Id = r.Id,
        Title = r.Title,
        Tags = r.Tags.Select(rt => rt.TagId)
    })
    .ToList();
 类似资料:
  • 我已经将读上下文和写上下文分开了,现在我将在默认情况下在ReadOnlyContext中启用LazyLoading。我也使用了下面的方法,但不幸的是它不起作用。 我的模型: 我的ef版本: EntityFramework核心版本2.1.2 我得到了这个错误: “为警告‘Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingW

  • 考虑以下(非常简化的)实体: 在我的映射器中,我可以设置用户罚款,但是一旦执行以下代码(在数据库中保留任何更改之前)

  • 我从这个网站上读到了关于懒惰加载的内容。启用或禁用LazyLoding “如果我们请求已启用LazyLoading的学生列表,数据提供程序将从数据库中获取所有学生,但每个StudentAddress属性在显式访问该属性之前不会加载。” 此语句表示,当我将设置为true时,将不会加载相关数据。然而 如果我设置延迟加载启用=true,上面的代码返回所有特技与他们的老师和地址。我在这里错过了什么?有人能

  • 我正在使用启用延迟加载的实体框架5。我有以下代码: 但这有意义吗?我想确保公共属性订阅从不为null。由于虚拟实体框架覆盖了getter和setter以提供延迟加载功能。 我需要这个字段还是我可以只使用一个自动属性,如果没有订阅,我得到一个空列表?

  • 我在亲子关系中有几个实体:家庭(父母)和更新(孩子)。我想阅读没有相应更新的家庭列表。只有17个家庭,但大约有60,000个更新,所以我真的不想要更新。 我使用EntiesToDTO从Family实体生成DTO,并创建一个汇编器来将Family实体转换为FamilyDTO。汇编器的ToDTO方法如下所示: 当我运行汇编程序时,我发现每个生成的FamilyDTO都填充了Updates\u ID列表,

  • 当我从主viewController重定向到另一个viewController时,我得到了这个。 错误: Lazy 加载 NSBundle MobileCoreServices.framework, 已加载MobileCoreServices.framework, system group . com . apple . configuration profiles的系统组容器路径为/Users/