Составлять запросы по моделям данных сущностей
Есть ли способ составлять запросы из 2 разных моделей сущностей, если модели попадают в одну и ту же базу данных?
У меня есть такой сценарий: у меня есть структура, которая использует EF для доступа к данным.(EDM 1) У меня есть клиентское приложение, которое использует службы инфраструктуры, а также использует EF для собственного доступа к данным.(EDM2)
Есть ситуации, когда мне нужно составить запросы и объединить сущности, которые охватывают 2 EDM.
Есть ли способ сделать это без получения данных в памяти от первого EDM, а затем применить дополнительные предикаты / объединения в памяти от сущностей 2-го EDM?
Я надеюсь, что я формулирую это правильно
РЕДАКТИРОВАТЬ@Ladislav Mrnka: Первый EDM - это уровень доступа к данным для многократно используемой платформы. Нет смысла связывать сгенерированные EF сущности из этого EDM с сущностями потребляющего клиента. Если бы я это сделал, это лишило бы возможности API повторно, и мне пришлось бы иметь дело с дополнительным раздуванием (метаданные EF и таблицы БД клиента) каждый раз, когда я хотел заново развернуть фреймворк. Также это сделает управление моделью в конструкторе громоздким.
В настоящее время я использую то, что вы упоминаете в пункте 7 в качестве решения, и производительность ужасна из-за того, что мне приходится в конечном итоге возвращать больше данных (т. Е. Объектов), чем необходимо, из инфраструктуры с использованием EDM1, а затем отфильтровывать ненужные данные. на основе предикатов / условий, основанных на значении свойств от сущностей во втором EDM. Конечным результатом является значительное снижение производительности и несчастный администратор базы данных.
По этой причине я в итоге выдвинул логику, необходимую для извлечения сущностей в SPROC, в которой я могу получить доступ к таблицам, которые используют оба EDM, и применить необходимые предикаты, и выполнить весь запрос в БД, а не переносить данные в память. а затем отфильтровывать ненужные. Недостатком является то, что я не могу использовать LINQ
Пункт 8, который вы упоминаете, звучит интересно, но из того, что он звучит, я сомневаюсь, что вы набираете сильные тексты во время разработки или нет? Можете ли вы загрузить пример кода где-нибудь, чтобы я смог его опробовать?
1 ответ
Важное редактирование
Нет поддержки в достижении этого двумя ObjectContext
типы. Ваш запрос всегда должен выполняться против одного ObjectContext
,
Наверное, лучший путь: это было достаточно интересно, чтобы я сам попробовал. Я начал с очень простой идеи. Два файла EDMX (используются с генераторами POCO T4), каждый из которых содержит один объект. Я беру описание метаданных из второй строки подключения и добавляю его в первую строку подключения. я использовал ObjectContext
а также ObjectSet
непосредственно. Сделав это, я смог запросить и изменить обе сущности из одного ObjectContext
пример. Я также попытался создать сущности, объединяющие запросы из обеих моделей, и это сработало. Это, очевидно, работает, только если оба EDMX отображаются в одну и ту же базу данных (одна и та же строка соединения с БД).
Важной частью является строка соединений:
<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="Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Эта строка подключения содержит метаданные из двух моделей - FirstModel.edmx и SecondModel.edmx.
Другая проблема заключается в том, чтобы заставить EF использовать сопоставление из обоих этих файлов. Каждый файл EDMX должен определять уникальный контейнер для SSDL и CSDL. ObjectContext
предлагает недвижимость под названием DefaultContainerName
, Это свойство может быть установлено напрямую или через некоторые перегрузки конструктора. Установив это свойство, вы связываете ObjectContext
экземпляр в один EDMX - для этого сценария вы не должны устанавливать это свойство. Опуская DefaultContainerName
может иметь некоторые последствия, потому что некоторые функции и объявления могут перестать работать (вы получите ошибки во время выполнения). У вас не должно быть проблем с POCO, если вы не хотите использовать некоторые расширенные функции. Скорее всего, у вас возникнут проблемы, если вы используете объекты 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's 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, которое сопоставлено с новой сущностью).
- Определите новый тип для результата запроса (свойства типа должны иметь те же имена, что и возвращаемые столбцы в запросе) и использовать ExecuteStoreQuery из ObjectContext (только в EF4).
Разделите запрос на две части, каждая из которых выполняется отдельно в своем собственном контексте, и используйте linq-to-objects для получения результата. Мне не нравится это решение.
Это только идея высокого уровня - я не пробовал и не знаю, работает ли это. Как описано выше, отображение во время выполнения зависит от содержимого
MetadataWorkspace
экземпляр, который заполняется изEntityConnection
,EntityConnection
также предоставляет конструктор, который получаетMetadataWorkspace
экземпляр напрямую. Так вообще если бы можно было заполнитьMetadataWorkspace
из нескольких EDMX вам не понадобится несколько экземпляров ObjectContext, но ваше отображение будет по-прежнему разделено на два EDMX. Мы надеемся, что это позволит вам писать собственные запросы Linq поверх двух файлов сопоставления). Изменить: Это должно быть возможно, потому что это именно то, что делает EF, если вы определяете несколько отображений в строке подключения.Использование CSDL Использование функции для разбиения модели на несколько повторно используемых частей.