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, но вместо того, чтобы передавать их в представление, вы возвращаете их вызывающему.

Возможно, вы не можете использовать его во всех случаях, но часто это выполнимый компромисс.