我在使用实体框架核心(v2.0.1)将实体模型转换为DTO时遇到了问题。基本上,它正在进行懒加载,而我不想要它。这里是一个简单的.NET Core控制台应用程序(使用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.Reports 更改为 var reports = dbContext.Reports.Include(r => r.Tags),但没有效果。
我甚至尝试将 Tags = r.Tags.Select(rt => rt.TagId) 更改为 Tags = r.Tags.Select(rt => rt.TagId).ToList(),但这会触发另外 26 次上述次要 SQL 查询。
最后,我绝望地尝试将 var reports = dbContext.Reports 更改为 var reports = dbContext.Reports.Include(r =>
r.Tags).ThenInclude((ReportTag rt) => rt.TagId),但可以理解地抛出异常,因为 ReportTag.TagId 不是导航属性。
有人有什么想法可以让它急切地加载到 ReportDto.Tags 属性中吗?