Выберите конкретные столбцы из базы данных, используя сначала код EF

У нас есть таблица с очень большим столом с столбцами 500 (я знаю, что кто-то это делает!)

Многие из этих столбцов действительно внешние ключи для других таблиц.

У нас также есть требование загружать некоторые связанные таблицы.

Есть ли какой-либо путь в Linq to SQL или Dynamic Linq, чтобы указать, какие столбцы будут извлекаться из базы данных? Я ищу оператор linq, который фактически использовал этот эффект для сгенерированного оператора SQL:

SELECT Id, Name FROM Book

Когда мы запускаем запрос reguar, созданный EF, SQL Server выдает ошибку, в которой вы достигли максимального количества столбцов, которые могут быть выбраны в запросе!!!

Любая помощь очень ценится!


Да, именно так, таблица имеет 500 столбцов и сама ссылается на наш инструмент, автоматически загружает отношения первого уровня, и это приводит к ограничению SQL по количеству столбцов, которые могут быть запрошены.

Я надеялся, что могу установить только загрузку ограниченных столбцов связанных объектов, таких как Id и Name (которые используются в пользовательском интерфейсе для просмотра записи пользователю)

Я полагаю, что другой вариант - контролировать, какие столбцы FK должны быть загружены. Однако это все еще остается проблемой для таблиц с бинарным или ntext столбцом, которые вы можете не захотеть загружать все время.

Есть ли способ связать несколько моделей (Entities) с одной и той же таблицей в Code First? Мы пытались сделать это, я думаю, что усилия потерпели неудачу.

Ответ 1

Да вы можете возвращать только подмножество столбцов с помощью проецирования:

var result = from x in context.LargeTable
             select new { x.Id, x.Name };

Проблема: проекция и интенсивная загрузка не работают вместе. После того, как вы начнете использовать прогнозы или пользовательские соединения, вы меняете форму запроса, и вы не можете использовать Include (EF проигнорирует его). Единственный способ в таком сценарии - вручную включить отношения в проецируемый набор результатов:

var result = from x in context.LargeTable
             select new {
                 Id = x.Id,
                 Name = x.Name,
                 // You can filter or project relations as well
                 RelatedEnitites = x.SomeRelation.Where(...) 
             };

Вы также можете проецировать определенный тип BUT, но не должен отображаться конкретный тип (поэтому вы не можете, например, проектировать объект LargeTable из моего примера). Проецирование отображаемого объекта может выполняться только по материализованным данным в Linq-to-objects.

Edit:

Возможно, есть некоторые недоразумения в отношении того, как работает EF. EF работает поверх объектов - объект - это то, что вы сопоставили. Если вы сопоставляете 500 столбцам с сущностью, EF просто использует этот объект, как вы его определили. Это означает, что запрос на загрузку объекта и сохранение сохраняет объект.

Почему он работает таким образом? Объект рассматривается как структура атомных данных, и его данные могут быть загружены и отслеживаться только один раз - это ключевая функция для способности правильно сохранять изменения в базе данных. Это не означает, что вам не нужно загружать только подмножество столбцов, если вам это нужно, но вы должны понимать, что загрузка подмножества столбцов не определяет ваш исходный объект - это считается произвольным представлением данных в вашей организации. Это представление не отслеживается и не может сохраняться в базе данных без дополнительных усилий (просто потому, что EF не содержит никакой информации о происхождении проекции).

EF также помещают некоторые дополнительные ограничения на способность сопоставлять сущность

  • Каждая таблица обычно может отображаться только один раз. Зачем? Опять же, поскольку таблица сопоставления несколько раз для разных объектов может нарушить способность правильно сохранять эти объекты - например, если какой-либо неклассический столбец отображается дважды, и вы загружаете экземпляр обоих объектов, сопоставленных с одной и той же записью, которые из отображаемых значений будут использоваться во время сохранение изменений?
  • Есть два исключения, которые позволяют вам сопоставлять таблицу несколько раз
    • Таблица на наследование иерархии - это сопоставление, в котором таблица может содержать записи из нескольких типов сущностей, определенных в иерархии наследования. Столбцы, сопоставленные базовому объекту в иерархии, должны совместно использоваться всеми объектами. Каждый тип производного объекта может иметь свои собственные столбцы, сопоставленные с его конкретными свойствами (другие типы сущностей имеют эти столбцы всегда пусты). Нельзя разделить столбец для производных свойств среди нескольких объектов. Также должен быть один дополнительный столбец, называемый дискриминатором, указывающий EF, какой тип сущности хранится в записи, - эти столбцы не могут быть отображены как свойство, поскольку он уже отображается как дискриминатор типа.
    • Разделение таблиц - это прямое решение для ограничения отображения одиночной таблицы. Это позволяет вам разбивать таблицу на несколько объектов с некоторыми ограничениями:
      • Между объектами должно быть взаимно однозначное отношение. У вас есть один центральный объект, используемый для загрузки основных данных, и все остальные объекты доступны через свойства навигации из этого объекта. Желательная загрузка, ленивая загрузка и явная загрузка обычно работают.
      • Отношение вещественно 1-1, так что обе части или отношение всегда должны существовать.
      • Сущности не должны делиться каким-либо свойством, кроме ключа - это ограничение разрешит начальную проблему, потому что каждое изменяемое свойство отображается только один раз
      • Каждый объект из таблицы split должен иметь свойство отображаемого ключа
      • Вставка требует, чтобы весь граф объекта был заполнен, поскольку другие объекты могут содержать сопоставленные требуемые столбцы.

Linq-to-Sql также содержит возможность отмечать столбец как ленивый, но эта функция в настоящее время недоступна в EF - вы можете голосовать за эту функцию.

Это приводит к вашим вариантам оптимизации

  • Использовать прогнозы для получения "представления" только для чтения для объекта
    • Вы можете сделать это в запросе Linq, как я показал в предыдущей части этого ответа.
    • Вы можете создать представление базы данных и отобразить его как новый "объект"
    • В EDMX вы также можете использовать Defining query или Query view для инкапсуляции проекции SQL или ESQL в ваше сопоставление.
  • Использование разделения таблиц
    • EDMX позволяет без проблем разбивать таблицу на многие объекты.
    • Код сначала позволяет вам разбивать таблицуно есть некоторые проблемы, когда вы разделяете таблицу на более чем два объекта (я думаю, для каждого типа сущности требуется, чтобы свойство навигации имело все свойства сущности из таблицы split, что делает его очень трудным для использования).

Ответ 2

Создайте хранимые процедуры, которые запрашивают количество необходимых столбцов, а затем вызовите сохраненные procs из кода.