Составление запросов для моделей данных сущностей

Есть ли способ составить запросы от двух разных моделей сущностей, если модели попадают в одну и ту же базовую базу данных.

У меня есть сценарий: У меня есть структура, которая использует EF для доступа к данным (EDM 1) У меня есть клиентское приложение, которое использует службы фреймворка, а также использует EF для собственного доступа к данным. (EDM2)

Есть ситуации, когда мне нужно составлять запросы и присоединяться к объектам, которые охватывают 2 EDM.

Есть ли способ сделать это, не получая данные в памяти из первого EDM, а затем применять дополнительные предикаты/объединения в памяти от объектов второго EDM?

Надеюсь, я правильно сформулирую это.

ИЗМЕНИТЬ @Ladislav Mrnka: Первый EDM - это уровень доступа к данным для многоразовой системы. Не имеет смысла связывать созданные EF объекты из этого EDM с те, которые потребляют клиент Это побеждает многократное использование API, если я это сделаю, и мне придется переносить дополнительную набухание (Метаданные EF и таблицы БД клиента) каждый раз, когда я хотел перераспределить фреймворк. Кроме того, это упростило бы управление моделью в дизайнере.

В настоящее время я использую то, что вы упоминаете в п. 7, как solutuon, и производительность ужасающая из-за того, что мне приходится возвращать больше данных (т.е. сущностей), чем нужно из фреймворка, используя EDM1, а затем отфильтровать те, которые не нужны на основе предикатов/условий, основанных на значении свойства от объектов во втором EDM. Конечный результат - огромная деградация производительности и несчастливый DBA.

По этой причине я в конечном итоге нажал логику, необходимую для извлечения объектов на SPROC, в котором я могу получить доступ к таблицам, которые используют EDM и применяют предикаты, необходимые и весь запрос выполняется в БД, в отличие от переноса данных в память а затем отфильтровать ненужные. Да, я не могу использовать LINQ

Пункт 8, который вы упоминаете, звучит интересно, но из того, что звучит, я сомневаюсь, что вы получаете сильную печать во время разработки, или вы? Можете ли вы загрузить образец кода где-нибудь, чтобы я мог попробовать?

Ответ 1

Важное изменение

Нет поддержки для достижения этого с помощью двух типов ObjectContext. Ваш запрос всегда должен выполняться в одиночном ObjectContext.

Вероятно, лучший способ: Это было достаточно интересно для меня, чтобы попробовать это сам. Я начал с очень простой идеи. Два файла EDMX (используемые с генераторами POCO T4), каждый из которых содержит единый объект. Я беру описание метаданных из второй строки подключения и добавляю ее к первой строке подключения. Я использовал ObjectContext и ObjectSet напрямую. Сделав это, я смог запросить и изменить оба объекта из одного экземпляра ObjectContext. Я также попытался создать запрос, соединяющий объекты с обеих моделей, и он сработал. Очевидно, что это работает, только если обе карты EDMX относятся к одной и той же базе данных (такая же строка соединения db).

Важной частью является строка соединений:

<configuration>
  <connectionStrings>
    <add name="TestEntities" connectionString="metadata=res://*/FirstModel.csdl|res://*/FirstModel.ssdl|res://*/FirstModel.msl|res://*/SecondModel.csdl|res://*/SecondModel.ssdl|res://*/SecondModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

Эта строка содержит метаданные из двух моделей - FirstModel.edmx и SecondModel.edmx.

Другая проблема заключается в том, чтобы заставить EF использовать сопоставление обоих этих файлов. Каждый файл EDMX должен определять уникальный контейнер для SSDL и CSDL. ObjectContext предлагает свойство под названием DefaultContainerName. Это свойство может быть установлено непосредственно или через некоторые перегрузки конструктора. После того как вы установите это свойство, вы привязываете свой экземпляр ObjectContext к одиночному EDMX - для этого сценария вы не должны устанавливать это свойство. Опускание DefaultContainerName может иметь некоторые последствия, поскольку некоторые функции и объявления могут перестать работать (вы получите ошибки во время выполнения). У вас не должно быть проблем с POCO, если вы не хотите использовать некоторые дополнительные функции. Вероятнее всего, вы будете иметь proplems, если вы используете объекты Entity (тяжелые объекты EF). Все методы, использующие сущности, определенные как строки, зависят от контейнера. В связи с этим я предлагаю использовать такую ​​конфигурацию только при необходимости - для запросов с поперечными моделями.

Последняя проблема заключается в генерации сущностей и "строго типизированных" полученных ObjectContext. Способ перехода - это изменить шаблон T4, чтобы один шаблон читал данные из нескольких файлов EDMX и генерировал сущности контекста для всех из них - я уже делаю это в своем проекте, и он работает. Реализация по умолчанию T4 не соответствует требуемому подходу, описанному в предыдущем абзаце. Производный ObjectContext от реализации по умолчанию T4 зависит от одного контейнера EDMX и объекта.


Эта часть была написана до предыдущего редактирования.

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

ORM, как структура сущности, работает поверх сопоставления между миром объектов и миром базы данных. В EF мир объектов описывается CSDL, мир базы данных описывается как SSDL и сопоставление между ними описывается как MSL (все это всего лишь XML с хорошо известной схемой). Во время разработки эти описания являются частью модели, хранящейся в файле EDMX. Во время компиляции эти описания извлекаются из EDMX и по умолчанию включаются как файлы ресурсов в сборку сборки.

При создании экземпляра ObjectContext он получает строку соединений, содержащую ссылку на файлы ресурсов CSDL, SSDL и MSL. SSDL или MSL не указывают элемент include для добавления информации из других файлов. CSDL предлагает элемент, который позволит повторно использовать существующее сопоставление, но эта функция не поддерживается дизайнером. ConnectionString используется для инициализации экземпляра EntityConnection, который, в свою очередь, используется для инициализации ObjectContext MetadataWorkspace (информация о сопоставлении времени выполнения). Кроме того, ObjectContext не предоставляет никаких функций вложения нескольких контекстов в hiearchy. Строка подключения не может содержать ссылку на несколько экземпляров этих файлов. Изменить: возможно. Я просто протестировал его. См. Начальные абзацы.

Когда вы запускаете запрос Linq или ESQL на экземпляр ObjectContext, вы можете использовать MSL для сопоставления ваших объектов или классов POCO (определенных CSDL) в запросе БД (определяемом описанием SSDL таблиц базы данных). Если он не имеет этой информации, он не будет работать (и он не может иметь эту информацию, если он хранится в отдельном EDMX).

Итак, как решить эту проблему? Существует несколько способов:

  • Всегда учитывать: Объединить ваше сопоставление в один файл (если для одной базы данных используется несколько файлов). Это предполагаемый способ использования EF, и, как вы упомянули, вы запрашиваете одну и ту же БД, поэтому две модели EF не нужны.
  • Повторяющееся описание сущности во второй модели. Если вы используете EF4 и POCO, вы можете сопоставить одинаковые описания из нескольких моделей в одно определение класса POCO. Мне не нравится это решение, но иногда оно может помочь.
  • Определите DB View или хранимую процедуру, содержащую ваш запрос (или ядро ​​вашего запроса) и сопоставьте его в одной модели с новым объектом.
  • Используйте DefiningQuery в одной модели (вам, вероятно, понадобится третий, если вы используете функцию "Обновление из базы данных" ) и сопоставьте ее с новым объектом. DefiningQuery - это настраиваемый SQL-запрос, определенный в SSDL вместо описания таблицы или описания.
  • Используйте Функция с пользовательским CommandText, определяющим запрос БД. Он похож на использование DefiningQuery и имеет такое же ограничение. Вы должны вручную (в EDMX) отобразить результат функции в новый сложный тип (другое отличие от DefiningQuery, которое отображается на новый объект).
  • Определить новый тип для результата запроса (свойства типа должны иметь одинаковые имена, как возвращенные столбцы в запросе) и использовать ObjectContext ExecuteStoreQuery ( только в EF4).
  • Разделите запрос на две части, каждая из которых выполняется отдельно в своем собственном контексте и использует linq-to-objects для получения результата. Мне не нравится это решение.

  • Это только идея высокого уровня - я не пробовал, и я не знаю, работает ли она. Как описано выше, отображение времени выполнения зависит от содержимого экземпляра MetadataWorkspace, который заполняется из EntityConnection. EntityConnection также предоставляет конструктор, который получает экземпляр MetadataWorkspace напрямую. Поэтому, как правило, если бы можно было заполнить MetadataWorkspace из нескольких EDMX, вам не понадобятся несколько экземпляров ObjectContext, но ваше сопоставление будет по-прежнему разделяться на два EDMX. Это, надеюсь, позволит вам писать пользовательские запросы Linq поверх двух файлов сопоставления). Изменить: Это должно быть возможно, потому что это именно то, что делает EF, если вы определяете несколько сопоставлений в строке соединения.

  • Используйте CSDL, используя функцию, чтобы разбить модель на несколько повторно используемых частей.