2009-03-18 12 views
43

Sembra che serializzare oggetti Entity Framework in JSON non sia possibile utilizzando il DataContractJsonSerializer nativo di WCF o il serializer JavaScript nativo di ASP.NET. Ciò è dovuto al problema del conteggio dei riferimenti che entrambi i serializzatori rifiutano. Ho anche provato Json.NET, che fallisce anche in modo specifico su un problema di conteggio dei riferimenti.Serializzare oggetti Entity Framework in JSON


Edit: Json.NET può ora serialize and deserialize Entity Framework entities.


I miei oggetti sono oggetti Entity Framework, che sono sovraccarichi per eseguire funzionalità di business aggiuntive (ad es. L'autenticazione, etc.) e non voglio per decorare queste classi con gli attributi specifici della piattaforma, ecc come voglio presentare un'API indipendente dalla piattaforma.

realtà ho bloggato sui singoli passi sono andato anche se a https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/

Ho perso qualcosa di ovvio?

+0

Sì serial JSon.NET ma desidero restituire IQueryable non stringa json! Se dovessi restituire IQueryable potrei utilizzare di OData. –

+0

Link su bloggingabout.net. È rotto –

+0

@MichaelFreidgeim Sì, l'ho capito quando qualcuno ha cancellato un altro post. Che era bello Sembra che il blog abbia deciso di cancellare il mio blog. Non felice. Posso solo scusarmi. Mi sono preso il tempo di guardare indietro agli archivi Internet e ripubblicarli in un altro luogo. –

risposta

71

Il modo in cui lo faccio è proiettando i dati che desidero serializzare in un tipo anonimo e serializzandolo. Ciò garantisce che solo le informazioni che effettivamente desidero nel JSON siano serializzate e che inavvertitamente non serializzi qualcosa più in basso nel grafico dell'oggetto. Ecco come si presenta:

var records = from entity in context.Entities 
       select new 
       { 
        Prop1 = entity.Prop1, 
        Prop2 = entity.Prop2, 
        ChildProp = entity.Child.Prop 
       } 
return Json(records); 

Trovo tipi anonimi quasi ideale per questo. Il JSON, ovviamente, non si preoccupa di quale tipo è stato usato per produrlo. E i tipi anonimi ti danno completa flessibilità su quali proprietà e strutture hai inserito nel JSON.

+2

grazie per questo, ho navigato per ore su questo !! – Peter

+1

Ottima soluzione. Esiste un modo valido per deserializzare un oggetto javascript in un oggetto EF? –

+0

Samuel, il raccoglitore modello predefinito può generalmente far fronte ai tipi EF. Ma preferisco deserializzare su un modello specifico di modifica, quindi mappare al tipo EF. –

17

Microsoft ha commesso un errore nel modo in cui hanno trasformato gli oggetti EF in contratti di dati. Includevano le classi base e i collegamenti posteriori.

La soluzione migliore è creare classi equivalenti di oggetti Data Transfer per ciascuna delle entità che si desidera restituire. Questi includerebbero solo i dati, non il comportamento, e non le parti specifiche di EF di un'entità. Dovresti anche creare metodi per tradurre da e verso le tue classi DTO.

I servizi restituirebbero quindi gli oggetti di trasferimento dati.

+0

C'è un'opzione ora per rendere la serializzazione unidirezionale. È possibile che l'opzione non esistesse quando hai fatto questo post. Ho pensato di aggiungerlo nel caso in cui altri lo incontrassero in futuro. – Yuck

+12

@ Yuck: aggiungi un collegamento a informazioni su questa funzione, per favore. –

+0

Per quanto ne so EF non ha una tale impostazione. Questo è solo per Linq-to-SQL. – Ziad

1

Un'altra soluzione se si desidera una migliore coerenza del codice è utilizzare JavaScriptConverter che gestirà le dipendenze di riferimento circolari e non serializzerà tali riferimenti.

ho bloggato su qui:

http://hellowebapps.com/2010-09-26/producing-json-from-entity-framework-4-0-generated-classes/

+1

Accetto Mehal. Ho esteso il tuo esempio per gestire altri casi nella mia risposta qui http://stackoverflow.com/questions/4053161/serializing-entity-framework-problems –

+0

Vorrei che questo codice funzionasse ... – jocull

+0

Il link è rotto –

2

La mia soluzione era di rimuovere semplicemente il genitore di riferimento sulle mie entità figlio.

Quindi nel mio modello, ho selezionato la relazione e modificato il riferimento padre come Interno anziché Pubblico.

Potrebbe non essere una soluzione ideale per tutti, ma ha funzionato per me.

+0

Questo sembra funzionare abbastanza bene! – Farinha

1

FYI ho trovato una soluzione alternativa

È possibile impostare il rapporto genitori come privati ​​in modo quindi le proprietà non sono esposti durante la traduzione di rimuovere il ciclo di proprietà infinito

1

ho lottato con questo problema per giorni,

Soluzione. Dentro la tua finestra edmx. - fare clic destro e aggiungere il codice oggetto generazione - Selezionare la scheda Codice - selezionare EF 4x.POCOC Entity Generator

Se non lo vedi, allora si dovrà installare con NuGet, ricerca di EF.

Il generatore di entità genererà tutto il tipo complesso e l'oggetto entità in classi semplici da serializzare in json.

1

Ho risolto il problema ottenendo solo i tipi di oggetto dallo spazio dei nomi di sistema, quindi li ho convertiti in dizionario e li ho aggiunti all'elenco. Funziona bene per me :)

Sembra complicato, ma questa era l'unica soluzione generica che ha funzionato per me ... Sto usando questa logica per un aiutante che sto facendo, quindi è per un uso speciale dove Devo essere in grado di intercettare ogni tipo di oggetto nell'oggetto entità, forse qualcuno potrebbe adattarlo al suo uso.

List<Dictionary<string, string>> outputData = new List<Dictionary<string, string>>(); 

// convert all items to objects 
var data = Data.ToArray().Cast<object>().ToArray(); 

// get info about objects; and get only those we need 
// this will remove circular references and other stuff we don't need 
PropertyInfo[] objInfos = data[0].GetType().GetProperties(); 
foreach (PropertyInfo info in objInfos) { 
    switch (info.PropertyType.Namespace) 
    { 
      // all types that are in "System" namespace should be OK 
      case "System": 
       propeties.Add(info.Name); 
       break; 
    } 
} 
Dictionary<string, string> rowsData = null; 
foreach (object obj in data) { 
    rowsData = new Dictionary<string, string>(); 
    Type objType = obj.GetType(); 
    foreach (string propertyName in propeties) 
    { 
//if You don't need to intercept every object type You could just call .ToString(), and remove other code 
     PropertyInfo info = objType.GetProperty(propertyName); 
     switch(info.PropertyType.FullName) 
     { 
       case "System.String": 
        var colData = info.GetValue(obj, null); 
        rowsData.Add(propertyName, colData != null ? colData.ToString() : String.Empty); 
        break; 
//here You can add more variable types if you need so (like int and so on...) 
      } 
     } 

     outputData .Add(rowsData); // add a new row 
} 

"OutputData" è sicuro per JSON codificare ... spero che qualcuno troverà questa soluzione utile. È stato divertente scriverlo :)

2

Sulla base della risposta @Craig Stuntz e simile a un DTO, per la mia soluzione ho creato una classe parziale del modello (in un file separato) e un metodo di oggetto di ritorno con come voglio usando solo le proprietà che saranno necessarie.

namespace TestApplication.Models 
{ 
    public partial class Employee 
    { 
     public object ToObject() 
     { 
      return new 
      { 
       EmployeeID = EmployeeID, 
       Name = Name, 
       Username = Username, 
       Office = Office, 
       PhoneNumber = PhoneNumber, 
       EmailAddress = EmailAddress, 
       Title = Title, 
       Department = Department, 
       Manager = Manager 
      }; 
     } 
    } 
} 

E poi lo chiamano semplicemente il mio ritorno:

var employee = dbCtx.Employees.Where(x => x.Name == usersName).Single(); 
return employee.ToObject(); 

penso che la risposta accettata è più semplice e veloce, mi basta usare il mio metodo per tenere tutti i miei rendimenti costanti e secco.

Problemi correlati