EF core, Трансляция запроса
Использую EF Core для работы с БД. Есть сущность БД, которая имеет ключ на другую таблицу
public class ListAdministration
{
public int Id { get; set; }
public int PositionId { get; set; }
public virtual ListPosition Position { get; set; }
}
Выполняю select c отложенной загрузкой связанных сущностей, то есть
_dbContext.ListAdministrations.AsNoTracking().Select(rec => new ListAdministrationDTO
{
Id = rec.Id
PositionName = rec.Position.Name
})
в SQL запрос транслируется корректно
SELECT c.id as Id, m.Name as PositionName
FROM ListAdministrations as c
JOIN ListPositions as m ON m.id = c.positionId
Я хочу вынести преобразование в DTO в отдельный метод расширения
public static ListAdministrationDTO ToDto(this ListAdministration administration)
{
return new ListAdministrationDTO
{
Id = rec.Id
PositionName = rec.Position.Name
}
}
И использовать как
_dbContext.ListAdministrations.AsNoTracking().Select(rec => rec.ToDto)
В этом случае код метода ToDto не транслируется в SQL, а выполняется после выборки из базы, то есть SQL запрос выглядит так
SELECT c.id as Id
FROM ListAdministrations as c
Можно ли без явного указания include() и использования отдельного метода ToDto приджоинить ListPosition (то есть получить аналогичный результат как в первом варианте)?
Ответы (1 шт):
Метод ToDTO должен возвращать тип Expression, чтобы он мог быть транслирован в SQL.
public static Expression<Func<ListAdministration, ListAdministrationDTO>> ToDto()
{
return administration => new ListAdministrationDTO
{
Id = administration.Id,
PositionName = administration.Position.Name
};
}
Обратите внимание, что у метода нет параметров!
Это не метод расширения. Он может быть статическим или экземплярным - это не важно.
Использование:
_dbContext.ListAdministrations.AsNoTracking().Select(ToDto());
Вызывать нужно именно так: Select(ToDto())!
Если написать Select(x => ToDto()), то выражение конвертируется в делегат. Таким образом Expression исчезнет.
Другой способ.
Пишем метод расширения, возвращающий IQueryable:
public static class Extensions
{
public static IQueryable<ListAdministrationDTO> ToDto(this IQueryable<ListAdministration> administrations)
{
return administrations.Select(administration => new ListAdministrationDTO
{
Id = administration.Id,
PositionName = administration.Position.Name
});
}
}
Использование:
_dbContext.ListAdministrations.AsNoTracking().ToDto();