Сводка
Из-за ограничений работы с устаревшей базой данных и моей собственной неопытности в логике доступа к данным у меня возникают значительные проблемы с производительностью при доступе к данным из базы данных.
Тем не менее, я создал представление базы данных, которое объединяет несколько таблиц / вложенных представлений и собирает информацию для всей моей совокупной иерархии, и это кажется наиболее эффективным способом (из подходов, которые я пробовал)доступа к записям из базы данных на основе запросов, которые я ожидаю выполнить.Я работаю с EF Core 3.0 и хочу узнать, могу ли я настроить его так, чтобы он заполнял всю совокупную иерархию на основе поиска в этом единственном представлении.
Для целей моего приложения мне нужно только запрашивать данных, не выполнять никаких обновлений.
Справочная информация
Я пытаюсь разработать приложение, которое позволяет менеджерам по продажам в филиале компанииотслеживать состояние активных заказов консультантов по продукту (менеджеров по продажам) в этом филиале.
Исходя из этой цели, я смоделировал домен приложения, как показано ниже.Филиалы состоят из множества консультантов по продуктам, каждый из которых отвечает за ряд заказов.Каждый заказ имеет индивидуальное сопоставление с продаваемым автомобилем.
![](https://i.stack.imgur.com/ws3Wl.png)
В моей базе данных я создал представление, которое возвращает все данные, необходимые для заполнения всего дерева агрегатов:
![](https://i.stack.imgur.com/aU0y8.png)
Приведенный ниже код показывает то, что я пробовал до сих пор, в котором я применяю традиционный подход сопоставления каждой сущности в объединенном корне с собственной таблицей / представлением:
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 на использование поиска, аналогичного тому, который используется для заполнения всего дерева агрегатов?Я знаком с разбивкой таблиц и уже использовал это для объединения информации о заказе и транспортном средстве в одном представлении, но я не уверен, можно ли это расширить до полной совокупности.