Проекция EF Core LINQ с вложенной извлеченной логикой не работаетC#

Место общения программистов C#
Ответить
Anonymous
 Проекция EF Core LINQ с вложенной извлеченной логикой не работает

Сообщение Anonymous »

Я пытаюсь выделить логику проекции для запросов EF Core LINQ в отдельные методы, чтобы сделать код более чистым или повторно использовать код для разных проекций?
Для повторного использования есть аналогичная публикация код в разделе «Могу ли я повторно использовать код для выбора пользовательского объекта DTO для дочернего свойства с помощью EF Core?», но выбранный ответ использует дополнительные библиотеки, и вопрос заключался в использовании вызова типа Select(Model.AsDto), который инкапсулирует лямбда-выражение.
Я хочу использовать простое решение и не хочу удалять лямбда-выражение. Я просто хочу извлечь часть сопоставления, которая создает новый объект, например (danceCoverImage, image) => Mappings.MapToImageItemResponse(danceCoverImage, image)).
Это отлично работает для одного вложенного уровня, а не для двух, как показано в примере ниже.
У меня есть пример проекции, который возвращает данные о местоположении с вложенными изображениями обложек. URI, ширина и высота изображения извлекаются путем объединения из коллекции изображений.

Код: Выделить всё

List Locations;

var query = dbContext.Location.AsNoTracking()
.Select(location => new LocationMLResponse(
location.Id.Value,
location.Name.ToStringDictionary(),
location.CoverImages
.Join(dbContext.Image.AsNoTracking(),
danceCoverImage => danceCoverImage.ImageId,
image => image.Id,
(danceCoverImage, image) => new ImageItemResponse(
danceCoverImage.ImageId.Value,
danceCoverImage.DisplayOrder,
danceCoverImage.Language == null ? null : danceCoverImage.Language.Tag,
danceCoverImage.ScreenSize == null ? null : danceCoverImage.ScreenSize.Value,
danceCoverImage.FocusPointX,
danceCoverImage.FocusPointY,
image.Uri.ToString(),
image.MetaData.Width,
image.MetaData.Height
)).ToList(),
location.Address.MapToDto(),
location.Created,
location.LastModified,
location.Version
));

Locations = await query.ToListAsync();
Я пытался извлечь методы для сопоставления:

Код: Выделить всё

var query = dbContext.Location.AsNoTracking()
.Select(location => MapToLocationResponse.MLResponse(dbContext, location));

internal static class MapToLocationResponse
{
public static LocationMLResponse MLResponse(VCDbContext dbContext, Location location)
{
return new LocationMLResponse(
location.Id.Value,
location.Name.ToStringDictionary(),
location.CoverImages
.Join(dbContext.Image.AsNoTracking(),
danceCoverImage => danceCoverImage.ImageId,
image => image.Id,
(danceCoverImage, image) => Mappings.MapToImageItemResponse(danceCoverImage, image)).ToList(),
location.Address.MapToDto(),
location.Created,
location.LastModified,
location.Version
);
}
}

internal static partial class Mappings
{
public static ImageItemResponse MapToImageItemResponse(ImageItem imageItem, Image image)
{
return new ImageItemResponse(
imageItem.ImageId.Value,
imageItem.DisplayOrder,
imageItem.Language == null ? null : imageItem.Language.ToString(),
imageItem.ScreenSize == null ? null : imageItem.ScreenSize.ToString(),
imageItem.FocusPointX,
imageItem.FocusPointY,
image.Uri.ToString(),
image.MetaData.Width,
image.MetaData.Height
);
}
}
Этот код создает следующий запрос:

Код: Выделить всё

SELECT [l].[LocationId], [l].[Created], [l].[CreatedBy], [l].[CreatedInNameOf], [l].[LastModified], [l].[LastModifiedBy], [l].[LastModifiedInNameOf], [l].[Name], [l].[TId], [l].[Version], [l].[Address_City], [l].[Address_CountryId], [l].[Address_CountryName], [l].[Address_DeliveryInstruction], [l].[Address_State], [l].[Address_Street], [l].[Address_StreetAffix], [l].[Address_StreetNumber], [l].[Address_ZipCode], [l0].[TId], [l0].[DisplayOrder], [l0].[FocusPointX], [l0].[FocusPointY], [l0].[ImageId], [l0].[Language], [l0].[LocationId], [l0].[ScreenSize]
FROM [VC].[Location] AS [l]
LEFT JOIN [VC].[LocationCoverImage] AS [l0] ON [l].[LocationId] = [l0].[LocationId]
ORDER BY [l].[LocationId]
Отсутствует соединение с таблицей изображений и выбор полей изображения.
Я пробовал сопоставление только с одним вложением:

Код: Выделить всё

 List Locations;

var query = dbContext.Location.AsNoTracking()//.AsSplitQuery()
.Select(location => new LocationMLResponse(
location.Id.Value,
location.Name.ToStringDictionary(),
location.CoverImages
.Join(dbContext.Image.AsNoTracking(),
danceCoverImage => danceCoverImage.ImageId,
image => image.Id,
(danceCoverImage, image) =>  Mappings.MapToImageItemResponse(danceCoverImage, image)).ToList(),
location.Address.MapToDto(),
location.Created,
location.LastModified,
location.Version
));

Locations = await query.ToListAsync();
Это работает. Проекция создает тот же запрос, что и полная проекция сверху.
(Примечание: с созданным запросом связана общая проблема, которую я опубликовал в разделе вопросов EF Core GitHub.
Это проблема с EF Core в целом или она просто связана с объединением? Можно ли использовать вложенный вызов или для этого необходимо использовать выражения?
Версия EF Core: 8.0.8

Поставщик базы данных: Microsoft.EntityFrameworkCore.SqlServer

Целевая платформа: NET 8.0

Операционная система: Win 11

Visual Studio 2022 17.11.4

Подробнее здесь: https://stackoverflow.com/questions/790 ... s-not-work
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»