2009-03-18 14 views
43

Wydaje się, że serializowanie obiektów Entity Framework w JSON nie jest możliwe przy użyciu macierzystego serializatora JavaScript DataContractJsonSerializer lub programu ASP.NET natywnego kodu JavaScript. Wynika to z problemów związanych z odliczaniem, które odrzucają seraliści. Próbowałem również Json.NET, co również nie powiedzie się konkretnie w przypadku licznika odwołań.Obiekty Serialize Entity Framework do JSON


Edit: Json.NET może teraz serialize and deserialize Entity Framework entities.


Moje obiekty są obiektami Entity Framework, które są przeciążone do wykonywania dodatkowych funkcji biznesowych (np. Uwierzytelnianie, itd.) I nie chcę, aby ozdobić tych klas z atrybutów specyficznych dla platformy itp jak chcę przedstawić interfejs API agnostyczny.

ja faktycznie napisał o poszczególnych krokach poszedłem choć https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/

Czy mogę pominięte coś oczywistego?

+0

Tak, serializacja JSon.NET, ale chciałbym zwrócić IQueryable nie ciąg znaków json! Gdybym wrócił IQueryable , mógłbym użyć OData. –

+0

Link na bloggingabout.net. Jest zepsuty –

+0

@MichaelFreidgeim Tak, zdałem sobie z tego sprawę, gdy ktoś usunął inny wpis. Co było miłe. Wygląda na to, że blog postanowił usunąć mojego bloga. Nieszczęśliwy. Mogę tylko przeprosić. Poświęciłem czas na przeglądanie archiwów internetowych i ponowne publikowanie w innym miejscu. –

Odpowiedz

71

Sposób, w jaki to robię, polega na rzutowaniu danych, które chcę przekształcić do postaci anonimowej i serializacji. Gwarantuje to, że tylko informacje, które faktycznie chcę w JSON, są serializowane i nieumyślnie serializuję coś dalej w dół wykresu obiektu. Wygląda to tak:

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

Uważam, że typy anonimowe są właśnie idealne do tego. JSON, oczywiście, nie dba o to, jaki typ został użyty do jego wytworzenia. Anonimowe typy zapewniają pełną elastyczność w zakresie właściwości i struktury, które można umieścić w JSON.

+2

dziękuję za to, przeglądam to wiele godzin !! – Peter

+1

Doskonałe rozwiązanie. Czy istnieje realny sposób deserializacji obiektu javascript z powrotem do obiektu EF? –

+0

Samuel, domyślny segregator modelu, zwykle radzi sobie z typami EF. Ale wolę deserializować do modelu specyficznego dla edycji, a następnie odwzorować na typ EF. –

17

Firma Microsoft popełniła błąd w sposobie przekształcania obiektów EF w umowy danych. Obejmowały one klasy bazowe i linki zwrotne.

Twoim najlepszym rozwiązaniem będzie stworzenie równoważnych klas obiektów transferu danych dla każdej jednostki, którą chcesz zwrócić. Obejmowałyby one tylko dane, a nie zachowanie, a nie specyficzne dla EF części jednostki. Można również tworzyć metody tłumaczenia na i ze swoich klas DTO.

Twoje usługi zwrócą następnie obiekty przenoszenia danych.

+0

Istnieje teraz opcja, aby dokonać serializacji w jedną stronę. Możliwe, że ta opcja nie istniała, gdy tworzysz ten wpis. Pomyślałem, że dodam to na wypadek, gdyby inni napotkali to w przyszłości. – Yuck

+12

@Yuck: proszę podać link do informacji na temat tej funkcji. –

+0

O ile mi wiadomo, EF nie ma takiego ustawienia. Dotyczy tylko Linq-SQL. – Ziad

1

Jeszcze jednym rozwiązaniem, jeśli chcesz mieć lepszą spójność kodu, jest użycie JavaScriptConverter, który będzie obsługiwać kołowe zależności referencyjne i nie będzie serializować takich odniesień.

mam blogu o tutaj:

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

+1

Zgadzam się z Mehal. Rozszerzyłem twój przykład, aby poradzić sobie z kilkoma innymi przypadkami w mojej odpowiedzi tutaj http://stackoverflow.com/questions/4053161/serializing-entity-framework-problems –

+0

Szkoda, że ​​ten kod nie zadziałał ... – jocull

+0

Link jest zepsuty –

2

Moje rozwiązanie było po prostu usunąć odwołanie macierzyste w moich jednostek podrzędnych.

Tak więc w moim modelu wybrałem relację i zmieniono odwołanie nadrzędne na Odwołanie wewnętrzne, a nie publiczne.

Może nie być idealnym rozwiązaniem dla wszystkich, ale dla mnie działa.

+0

To wydaje się działać całkiem nieźle! – Farinha

1

FYI znalazłem rozwiązanie alternatywne

Można ustawić relacji rodzic jako prywatny więc wtedy właściwości nie są narażone podczas tłumaczenia usunięcie nieskończoną pętlę nieruchomości

1

walczyłem z tym problemem przez kilka dni,

Rozwiązanie. Wewnątrz okna edmx. - kliknij prawym przyciskiem myszy i dodać element generowania kodu - Wybierz zakładkę Code - wybierz EF 4x.POCOC Entity Generator

Jeśli nie widzisz go, a następnie trzeba będzie zainstalować go z Nuget, wyszukiwania EF.

Generator encji wygeneruje wszystkie złożone typy obiektów i obiektów w proste klasy, aby przekształcić je w json.

1

Rozwiązałem go, pobierając tylko typy obiektów z przestrzeni nazw System, a następnie przekonwertowałem je na słownik, a następnie dodałem do listy. Działa dobrze dla mnie :)

Wygląda na skomplikowaną, ale to było jedyne ogólne rozwiązanie, które zadziałało dla mnie ... Używam tej logiki dla pomocnika, który robię, więc jest do specjalnego użytku, gdzie Muszę być w stanie przechwycić każdy typ obiektu w obiekcie podmiotu, być może ktoś mógłby go dostosować do jego użycia.

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" jest bezpieczna dla JSON kodowania ... nadzieję, że ktoś znajdzie rozwiązanie to pomocne. Pisanie go było fajne :)

2

Opierając się na odpowiedzi @Craig Stuntz i podobnej do DTO, dla mojego rozwiązania stworzyłem częściową klasę modelu (w osobnym pliku) i metodę obiektu powrotnego z tym, w jaki sposób chcą go używać tylko właściwości, które będą potrzebne.

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

I wtedy nazywają go po prostu w moim powrocie:

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

myślę, że przyjęte rozwiązanie jest bardziej szybkie i łatwe, wystarczy użyć mojej metody, aby zachować wszystkie moje zwrotów spójne i suche.