11

Mi sto rompendo la testa su questo problema. Ho trovato qualcosa su internet, ma non una risposta chiara. Il mio problema:WebApi con codice EF Prima genera un errore quando si ha una relazione figlio genitore

devo classi nella sezione Modello di un app MVC3 web: ParentClass e ChildClass Su ParentClass c'è una proprietà Figli di tipo List

ho usato EF primo codice, che genera ordinatamente un genitore tabella e una tabella figlio per me nel database.

Ora ho bisogno di un servizio REST che restituisca una lista o una singola ParentClass.

Quando rimuovo la proprietà Bambini dalla ParentClass non ci sono problemi. Ma con la propoerty Children, continuo a ricevere un errore.

Errore: "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."}

Alcuni codice:

Classi:

 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; } 
} 

Servizio:

[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; 

    } 

Non voglio ottenere il risultato quando callinh questo servizio. Che cosa sto facendo di sbagliato?

risposta

12

ho dovuto DisableProxyCreation nella configurazione contesto:

[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; 
     } 
} 

Questo ha funzionato per me bene.

+0

Proprio quello che stavo cercando. Conoscete eventuali aspetti negativi della disabilitazione di questo? – hooked82

+1

Ci sono molti aspetti positivi dei proxy, che tengono traccia degli aggiornamenti e così via. Nessun errore da dimenticare di includere dichiarazioni. Non ho ancora soluzioni per serializzare le entità proxi –

0

Sembra serializzare le classi proxy per i vostri POCO, la mia prima raccomandazione sarebbe quella di utilizzare il proxydatacontractresolver: http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx.

Inoltre vorrei lavorare per avere le cose scritte in modo esplicito durante il caricamento dei dati per l'invio di più di servizio web ... cioè

Cambiare classe padre per

public class ParentClass 
{ 
    public int ID { get; set; } 
    public string Name {get;set;} 
    public List<ChildrenClass> Children { get; set; } 

} 

Alter suo sito web per spegnere lazy loading: Disable lazy loading by default in Entity Framework 4

E specificare esplicitamente cosa si desidera caricare quando si restituiscono dati inviati sul filo.

[WebGet(UriTemplate = "")] 
public List<ParentClass> GetParents() 
{ 
    var result = db.Parents.Include("Children").ToList(); 
    return result; 

} 

Dai un'occhiata alla seguente risposta: Entity Framework Code First - Eager Loading not working as expected? per più avanzati includono chiamate.

Anche un consiglio da esperienza, non vorrei restituire le vostre classi di dati sul filo mentre formano un contratto per il consumatore del vostro servizio web. È meglio avere un altro insieme di classi in cui mappare i valori dei dati in.

In questo modo se le classi di dati cambiano, non è necessario modificare il client del servizio Web se non richiesto esplicitamente.

E l'utilizzo del paging è importante se si prevedono 1000 di righe nelle classi padre o figlio altrimenti si finisce con N + 1 selezionare, vedere: What is SELECT N+1?.

+1

Ho provato il DataContractResolver, ma questo non ha aiutato. La funzione disableproxy ha aiutato. Ma se ho capito bene dovrei separare i POCO compilati dal database dalle classi da utilizzare nei servizi. Ma ciò non significa che ogni oggetto debba essere duplicato, ovvero una ParentClass per l'utilizzo all'interno del sito e la logica di business e una ParentClass separata per l'utilizzo nel servizio. Non è un codice di duplicazione troppo? – Mounhim

+0

Utilizziamo DTO e Automapper per separare il nostro modello di risorse dal nostro modello di dominio. Ci sono molti vantaggi a questo inclusi convalida separata e strutture separate/diverse – suing

+0

Spesso è eccessivo usare duplicati per i POCO per N diversi usi, incluso il lavoro additivo e la manutenzione di mappe/xlats. Molti sviluppatori adottano l'approccio di definire con cura i propri POCO una volta e quindi utilizzarli per il trasferimento dei dati e l'accesso ai dati, in particolare su progetti più piccoli. Se arriva un momento in cui questo non funziona più (modifiche dello schema, refacters, ecc.), Devono essere definiti nuovi POCO e la mappatura eseguita come necessario. Questo tipo di shift/refactor non ha alcun effetto sui client Web, è solo un problema per i consumatori .NET di librerie di classi. Per esempio. dipendenti binari. –

0

In alcune situazioni una soluzione semplice consiste nell'utilizzare una classe wrapper in modo che tutte le proprietà esposte siano tipi noti.

In genere non si utilizzerà ObjectContext o DbContext nelle classi controller in modo tale che in un livello precedente (livello Business o Service) è possibile eseguire una traduzione rapida dagli oggetti provenienti dal DB in oggetti stile ViewModel, simile a quello che faresti in un'app MVC, ma invece di trasmetterli a una vista, li restituirai al chiamante.

Forse non è possibile utilizzarlo in tutti i casi, ma spesso è un compromesso praticabile.

Problemi correlati