繁体   English   中英

实体框架核心嵌套列表性能

[英]Entity Framework Core Nested List Performance

当我尝试向嵌套列表中添加其他项目时,我在实体框架核心性能方面遇到了困难。

举个例子:我有多个项目,项目包含多个房屋,房屋有多个立面,立面有多个windows。 如果我现在想向特定项目、房屋、立面添加额外的 window,我会这样做:

    public async Task SaveWindowAsync(Guid projectId, Guid houseId, Guid facadeId, WindowEntity windowEntity)
    {
        using (ProjectsDbContext context = new ProjectsDbContext())
        {
            var windowList = context.ProjectSet
                .Include(p => p.Houses)
                .ThenInclude(h => h.Facades)
                .ThenInclude(f => f.Windows)
                .First(p => p.Id == projectId).Houses
                .First(h => h.Id == houseId).Facades
                .First(f => f.Id == facadeId).Windows;

            windowList.Add(windowEntity);

            await context.SaveChangesAsync();
        }
    }

这在功能方面效果很好。 但是,当数据库增加时,性能会越来越慢。 是否有更高效的方式将项目添加到嵌套列表?

更新 1

我用这个包含 50 个项目的未来派对象创建了一个简单的测试数据库,每个项目有 10 个房子,每个房子有 10 个立面,每个立面有 10 个 windows。 这导致数据库大小约为 10Mb。

在测试中,我一个接一个地添加了 1000 Windows(没有散装):

上面提到的解决方案需要145s的总时间。

@David Browne 提到的解决方案——微软大约需要 54s

var facadeEntity = context.Set<FacadeEntity>()
    .Include(f => f.Windows)
    .Single(f => f.Id == facadeId);

facadeEntity.Windows.Add(windowEntity);

await context.SaveChangesAsync();

更新 2

正如@David Browne 推荐的那样,我在 window 中添加了一个 ForeignKey:

modelBuilder.Entity<FacadeEntity>()
.HasMany(f => f.Windows).WithOne()
.HasForeignKey(f => f.FacadeId)
.OnDelete(DeleteBehavior.Cascade);

保存是这样执行的:

context.Entry(windowEntity).Property(nameof(WindowEntity.FacadeId)).CurrentValue = facadeId;
context.Set<WindowEntity>().Add(windowEntity);
await context.SaveChangesAsync();

这个问题是一样的 windows 我有更长的添加时间。 1000 个 Windows 的持续时间约为 53 秒。

我目前只有一个“DbSet ProjectSet”,你会在上下文中添加一个额外的 DbSet 吗?

如果您没有为实体声明DbSet<T> ,请通过DbContext.Set<T>()访问它,例如:

public static async Task SaveWindowAsync(Guid projectId, Guid houseId, Guid facadeId, Window windowEntity)
{
    using (ProjectsDbContext context = new ProjectsDbContext())
    {
        var facade = context.Set<Facade>()
                            .Where(f => f.FacadeId == facadeId)
                            .Single();

        facade.Windows.Add(windowEntity);

        await context.SaveChangesAsync();
    }
}

这转化为:

SELECT TOP(2) [f].[FacadeId], [f].[HouseId]
FROM [Facade] AS [f]
WHERE [f].[FacadeId] = @__facadeId_0

接着:

INSERT INTO [Window] ([WindowId], [FacadeId])
VALUES (@p0, @p1)

假设Facade有一个单列主键。 如果它具有 (ProjectId,HouseId,FacadeId) 的复合键,则将它们添加到Where

但是,最好的方法是设置 Window.FacadeId 的外键属性,并且根本不加载外观。 在 EF Core 中,如果您没有外键属性,则可以使用影子属性执行此操作。 例如:

public static async Task SaveWindowAsync(Guid projectId, Guid houseId, Guid facadeId, Window windowEntity)
{
    using (ProjectsDbContext context = new ProjectsDbContext())
    {
        context.Entry(windowEntity).Property("FacadeId").CurrentValue = facadeId;
        context.Set<Window>().Add(windowEntity);

        await context.SaveChangesAsync();
    }
}

如果您尝试Window 添加到特定项目/房屋/立面,您可以直接在 WindowEntity 上设置 FacadeId 并保存吗? 据推测,Window 有一个 FacadeId 属性,就像 Facade 有一个 HouseId,而 House 有一个 ProjectId。 如果 Window 有其所有父母的 Id(不必要),那么也只需设置 House 和 Project Id。

public async Task SaveWindowAsync(Guid projectId, Guid houseId, Guid facadeId, WindowEntity windowEntity)
{
    using (ProjectsDbContext context = new ProjectsDbContext())
    {            
        windowEntity.FacadeId = facadeId;
        context.WindowSet.Add(windowEntity);
        await context.SaveChangesAsync();
    }
}

更新:如果您不想直接在实体上设置 facadeId,那么您可以加载外观,并设置其 Facade 属性而不是 Id。 如果您要继续使用该集合的实例,您也可以选择将 windowEntity 添加到 Facade 的 Windows 集合中。

public async Task SaveWindowAsync(Guid facadeId, WindowEntity windowEntity)
{
    using (ProjectsDbContext context = new ProjectsDbContext())
    {
        var facade = Facades.Single(x => x.Id == facadeId);
        windowEntity.Facade = facade;
        facade.Windows.Add(windowEntity);
        await context.SaveChangesAsync();
    }
}

您应该首先从 Windows DbSet 中的 select 然后加入 Facades 然后加入房屋您的查询应该看起来像这样

 var windowList = context.DbSet<Windows>().Where(w => w.Facade.Id== facadeId && w.Facade.House.Id == houseId && w.Facade.House.Project.Id == projectId)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM