Как я могу заполнить всю совокупную иерархию из одного представления базы данных - PullRequest
0 голосов
/ 27 сентября 2019

Сводка

Из-за ограничений работы с устаревшей базой данных и моей собственной неопытности в логике доступа к данным у меня возникают значительные проблемы с производительностью при доступе к данным из базы данных.

Тем не менее, я создал представление базы данных, которое объединяет несколько таблиц / вложенных представлений и собирает информацию для всей моей совокупной иерархии, и это кажется наиболее эффективным способом (из подходов, которые я пробовал)доступа к записям из базы данных на основе запросов, которые я ожидаю выполнить.Я работаю с EF Core 3.0 и хочу узнать, могу ли я настроить его так, чтобы он заполнял всю совокупную иерархию на основе поиска в этом единственном представлении.

Для целей моего приложения мне нужно только запрашивать данных, не выполнять никаких обновлений.

Справочная информация

Я пытаюсь разработать приложение, которое позволяет менеджерам по продажам в филиале компанииотслеживать состояние активных заказов консультантов по продукту (менеджеров по продажам) в этом филиале.

Исходя из этой цели, я смоделировал домен приложения, как показано ниже.Филиалы состоят из множества консультантов по продуктам, каждый из которых отвечает за ряд заказов.Каждый заказ имеет индивидуальное сопоставление с продаваемым автомобилем.

В моей базе данных я создал представление, которое возвращает все данные, необходимые для заполнения всего дерева агрегатов:

Приведенный ниже код показывает то, что я пробовал до сих пор, в котором я применяю традиционный подход сопоставления каждой сущности в объединенном корне с собственной таблицей / представлением:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Branch>(ConfigureBranch);
    modelBuilder.Entity<ProductConsultant>(ConfigureProductConsultant);
    modelBuilder.Entity<Order>(ConfigureOrder);
}

private static void ConfigureBranch(EntityTypeBuilder<Branch> builder)
{
    builder.ToView("Branch");
    builder.HasKey(b => b.Id);
    builder.Property(b => b.Id).HasColumnType("int");
    builder.HasMany(b => b.ProductConsultants).WithOne();
}

private static void ConfigureProductConsultant(EntityTypeBuilder<ProductConsultant> builder)
{
    builder.ToView("vw_OrderStatus_ProductConsultants");
    builder.HasKey(it => it.Id);
    builder.Property(p => p.Id).HasColumnType("int");
    builder.HasMany(p => p.Orders).WithOne();
}

private static void ConfigureOrder(EntityTypeBuilder<Order> builder)
{
    builder.ToView("vw_OrderStatus_Orders2");
    builder.HasKey(it => it.OrderId);
    builder.OwnsOne(o => o.Vehicle, vehicleBuilder =>
    {
        vehicleBuilder.Property(v => v.Registration).HasColumnName("VehicleRegistration");
        vehicleBuilder.Property(v => v.Make).HasColumnName("VehicleMake");
        vehicleBuilder.Property(v => v.Model).HasColumnName("VehicleModel");
        vehicleBuilder.Property(v => v.RetailPrice).HasColumnName("VehicleRetailPrice").HasColumnType("float");
    });

    builder.Property(o => o.OrderId).HasColumnType("int");
    builder.Property(o => o.Status)
        .HasColumnType("varchar(50)")
        .HasConversion(v => v.ToString(), v => ParseOrderStatusFromTable(v));

    builder.Property(o => o.Supplementaries)
        .HasConversion(v => string.Join(",", v), v => ParseSupplementariesFromTable(v));
}

Стандартный запросЯ мог бы захотеть выполнить поиск всех заказов, принадлежащих консультантам в определенном филиале:

var branch = _dbContext.Branches
    .Include(it => it.ProductConsultants)
    .ThenInclude(it => it.Orders)
    .Single(it => it.Id == 62);

При выполнении этого EF Core выполняет следующий поиск в базе данных:

SELECT [t].[ID],
       [t].[Name],
       [t2].[Id],
       [t2].[BranchId],
       [t2].[Name],
       [t2].[OrderId],
       [t2].[CustomerName],
       [t2].[DeliveryDate],
       [t2].[ProductConsultantId],
       [t2].[Status],
       [t2].[Supplementaries],
       [t2].[OrderId0],
       [t2].[VehicleMake],
       [t2].[VehicleModel],
       [t2].[VehicleRegistration],
       [t2].[VehicleRetailPrice]
FROM
(
    SELECT TOP (2)
           [b].[ID],
           [b].[Name]
    FROM [Branch] AS [b]
    WHERE [b].[ID] = 62
) AS [t]
    LEFT JOIN
    (
        SELECT [v].[Id],
               [v].[BranchId],
               [v].[Name],
               [t1].[OrderId],
               [t1].[CustomerName],
               [t1].[DeliveryDate],
               [t1].[ProductConsultantId],
               [t1].[Status],
               [t1].[Supplementaries],
               [t1].[OrderId0],
               [t1].[VehicleMake],
               [t1].[VehicleModel],
               [t1].[VehicleRegistration],
               [t1].[VehicleRetailPrice]
        FROM [vw_OrderStatus_ProductConsultants] AS [v]
            LEFT JOIN
            (
                SELECT [v0].[OrderId],
                       [v0].[CustomerName],
                       [v0].[DeliveryDate],
                       [v0].[ProductConsultantId],
                       [v0].[Status],
                       [v0].[Supplementaries],
                       [t0].[OrderId] AS [OrderId0],
                       [t0].[VehicleMake],
                       [t0].[VehicleModel],
                       [t0].[VehicleRegistration],
                       [t0].[VehicleRetailPrice]
                FROM [vw_OrderStatus_Orders2] AS [v0]
                    LEFT JOIN
                    (
                        SELECT [v1].[OrderId],
                               [v1].[VehicleMake],
                               [v1].[VehicleModel],
                               [v1].[VehicleRegistration],
                               [v1].[VehicleRetailPrice],
                               [v2].[OrderId] AS [OrderId0]
                        FROM [vw_OrderStatus_Orders2] AS [v1]
                            INNER JOIN [vw_OrderStatus_Orders2] AS [v2]
                                ON [v1].[OrderId] = [v2].[OrderId]
                        WHERE [v1].[VehicleRetailPrice] IS NOT NULL
                              AND
                              (
                                  [v1].[VehicleRegistration] IS NOT NULL
                                  AND
                                  (
                                      [v1].[VehicleModel] IS NOT NULL
                                      AND [v1].[VehicleMake] IS NOT NULL
                                  )
                              )
                    ) AS [t0]
                        ON [v0].[OrderId] = [t0].[OrderId]
            ) AS [t1]
                ON [v].[Id] = [t1].[ProductConsultantId]
    ) AS [t2]
        ON [t].[ID] = [t2].[BranchId]
ORDER BY [t].[ID],
         [t2].[Id],
         [t2].[OrderId];

Thisвыполнение операции может занять более 30 секунд, и в этот момент EF Core выдает исключение тайм-аута.

Однако я могу получить всю необходимую информацию, запустив следующий запрос, который завершается через 2 секунды:

SELECT * FROM dbo.vw_OrderStatus_Branches
WHERE BranchId = 62

Есть ли способ настроить EF Core на использование поиска, аналогичного тому, который используется для заполнения всего дерева агрегатов?Я знаком с разбивкой таблиц и уже использовал это для объединения информации о заказе и транспортном средстве в одном представлении, но я не уверен, можно ли это расширить до полной совокупности.

...