WebApi с кодом EF Сначала генерирует ошибку при наличии родительского дочернего отношения
Я ломаю голову над этой проблемой. Я нашел что-то в Интернете об этом, но не ясный ответ. Моя проблема:
У меня есть классы в разделе Model веб-приложения MVC3:
ParentClass и ChildClass
В ParentClass есть свойство Дети типа Список
Я использовал EF Code First, который аккуратно генерирует родительскую таблицу и дочернюю таблицу для меня в базе данных.
Теперь мне нужна служба REST, которая возвращает список или отдельный ParentClass.
Когда я удаляю свойство Children из ParentClass, проблем нет. Но с propoerty Children там я все время получаю сообщение об ошибке.
Ошибка: "The type System.Data.Entity.DynamicProxies.ParentClass_A0EBE0D1022D01EB84B81873D49DEECC60879FC4152BB115215C3EC16FB8003A was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}
Некоторые коды:
Классы:
public class ParentClass
{
public int ID { get; set; }
public string Name {get;set;}
public virtual List<ChildrenClass> Children { get; set; }
}
public class ChildrenClass
{
public int ID { get; set; }
public string MyProperty { get; set; }
}
Услуги:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyService
{
static MyContext db;
public MyService() { db = new MyContext(); }
[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
var result = db.Parents.ToList();
return result;
}
Я не получу результат, когда вызываю эту услугу. Что я делаю неправильно?
Ответы
Ответ 1
Мне пришлось отключить ProxyCreation в конфигурации контекста:
[OperationContract]
[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
using (DBContext context = new DBContext())
{
context.Configuration.ProxyCreationEnabled = false;
List<ParentClass> parents = context.Parents
.Include("Children")
.ToList();
return parents;
}
}
Это сработало для меня хорошо.
Ответ 2
Кажется, что сериализует прокси-классы для ваших POCOs, моей первой рекомендацией было бы использовать proxydatacontractresolver: http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx.
Также я бы работал над тем, чтобы все вещи были прописаны явно при загрузке данных для отправки через веб-службу... i.e.
Измените родительский класс на
public class ParentClass
{
public int ID { get; set; }
public string Name {get;set;}
public List<ChildrenClass> Children { get; set; }
}
Измените свой контент, чтобы отключить ленивую загрузку:
Отключить ленивую загрузку по умолчанию в Entity Framework 4
И явно укажите, что вы хотите загрузить при возврате отправленных данных по проводке.
[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
var result = db.Parents.Include("Children").ToList();
return result;
}
Посмотрите на следующий ответ: Код структуры Entity First - Eager Loading не работает как ожидается? для более сложных вызовов Include.
Кроме того, из опыта, я бы не возвращал ваши классы данных по проводам, поскольку они составляют контракт для потребителя вашего веб-сервиса. Лучше всего иметь другой набор классов, на которые вы сопоставляете свои значения данных.
Таким образом, если ваши классы данных меняются, вам не нужно менять клиента веб-службы, если это явно не требуется.
И использование пейджинга важно, если вы ожидаете 1000 строк в родительских или дочерних классах, иначе вы можете выбрать N + 1, см. Что такое SELECT N + 1?.
Ответ 3
В некоторых ситуациях простым решением является использование класса-оболочки, так что все отображаемые свойства являются известными типами.
Как правило, вы не будете использовать ObjectContext или DbContext в своих классах контроллера, так что на более раннем уровне (бизнес-или служебный уровень) вы можете быстро перевести объекты из базы данных в объекты стиля ViewModel, аналогичные к тому, что вы делали бы в приложении MVC, но вместо того, чтобы передавать их в представление, вы возвращаете их вызывающему.
Возможно, вы не можете использовать его во всех случаях, но часто это выполнимый компромисс.