簡體   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