Более ранние версии Entity Framework (т.е. до Core 2.1) использовали классы Proxy для моделей данных по умолчанию, когда он знает, что может лениво загружать данные. Например, если у вас был класс Parent
с коллекцией класса Children
, по умолчанию, когда вы загружаете объект Parent
через что-то вроде этого
var parent = entities.Parents.FirstOrDefault(p=>p.Id==pid)
Тогда EF будет - по умолчанию - не загружать связанных потомков до тех пор, пока вы в первый раз не попытаетесь ссылаться на них
, например, только в том месте, где вы пишете
var child = parent.Children.Where(c=>c.SomeProperty==true)
, и будет отправлен запрос fre sh SQL для получения ребенок. Это возможно благодаря наличию (прозрачного для вас) прокси-класса, сгенерированного во время выполнения для объекта Parent
, который обнаруживает, что вам нужен доступ к коллекции Children
, и выдает SQL, выполняет сопоставление и т. Д. c .
К сожалению, эти прокси-классы плохо поддаются - если вообще - - сериализации по разным причинам. Отсюда и сообщение об ошибке, которое вы получаете. В EF Core 2.1 все изменилось, поэтому отложенная загрузка по умолчанию отключена, и вы должны включить ее. Но если вы используете любую более раннюю версию (включая неосновные EF), то она включена по умолчанию.
Это также объясняет, почему вы создаете новую базу данных без внешних ключей, потому что EF не сможет выводить отношения к дочерним объектам, поэтому он не будет создавать прокси, то есть класс, с которым вы имеете дело, теперь называется тем, что мы называем POCO
(Plain Old CLR Object). Но вы лишаете себя (и EF) возможности иметь связанные объекты в реляционной базе данных, что, вероятно, не очень хорошо в долгосрочной перспективе:)
С точки зрения лучшего решения есть несколько вариантов Вы можете отключить создание прокси-сервера или получить весь объектный граф перед сериализацией:
var parent = entities.Parents.Include("Children").FirstOrDefault(p=>SomeCondition);
Это загрузит весь объект Parent
и все его Children
в одном go, и также избегайте проблемы; однако это не всегда идеально, потому что на самом деле вы не можете хотеть Children
сущностей каждый раз.
Но еще лучше, не подвергайте ваши модели EF напрямую, а используйте отображение на DTO (Объект передачи данных)
Я рекомендую DTO; самое большое преимущество использования DTO состоит в том, что вам не нужно показывать свои EF-сущности внешнему миру, потому что, например, могут быть их части, не относящиеся к потребителю, или вы можете захотеть объединить данные для какого-либо ребенка сборы до возвращения, et c.
Здесь есть отличное руководство , в котором более подробно рассматриваются эти темы.