Проектирование LINQ to SQL: Func vs Inline - PullRequest
4 голосов
/ 13 января 2011

Я обнаружил неожиданное поведение при использовании проекции в запросе LINQ to SQL с использованием Func. Пример кода объяснит лучше, чем слова.

Базовый лямбда-запрос L2S с использованием проекции:

db.Entities.Select(e => new DTO(e.Value));

Это переводит в желаемый SQL:

SELECT [t1].[Value]
FROM [Entity] AS [t1]

Однако, когда проекция помещается в Func следующим образом:

Func<Entity, DTO> ToDTO = (e) => new DTO(e.Value);

И называется так:

db.Entities.Select(e => ToDTO(e));

SQL теперь возвращает все столбцы в таблице, а не только один в проекции:

SELECT [t1].[Id], [t1].[Value], [t1].[timestamp], [t1].[etc...]
FROM [Entity] AS [t1]

Итак, мой вопрос: как мне инкапсулировать эту проекцию без создания экземпляра LINQ to SQL всей сущности?

Следует иметь в виду, что используемый мной DTO имеет защищенный конструктор по умолчанию, поэтому я не могу использовать инициализатор объекта. И поскольку класс DTO не может быть изменен, я должен создать подкласс для реализации этого поведения. Что хорошо, если это единственное решение.

Спасибо.

Edit:

Спасибо Брайану за решение. Ранее я пробовал выражение, но не смог понять синтаксис. Вот рабочий код:

Expression<Entity, DTO> ToDTO = (e) => new DTO(e.Value);

Тогда назовите это так:

db.Entities.Select(ToDTO);

Сначала я пытался назвать это так, что не скомпилируется. Это правильный синтаксис для вызова Func, но не Expression.

db.Entities.Select(e => ToDTO(e));

1 Ответ

5 голосов
/ 13 января 2011

Вам, вероятно, нужно создать Expression, а не Func

Expression<Func<Entity, DTO>> ToDTO = (e) => new DTO(e.Value);

Методы расширения IQueryable работают с Expression с, а не Func с

Проходяв Func вы, вероятно, вызываете метод расширения IEnumerable, поэтому Linq2Sql действует так, как он есть.

...