2011-09-30 9 views
7

così heres l'affare hoSoluzione da EntityFramework a JSON? (Un riferimento circolare rilevato durante la serializzazione di un oggetto di tipo ... DynamicProxies)

Modelli

public class News 
{ 

    public News() 
    { 
     this.Created = DateTime.Now; 
    } 

    public int Id { get; set; }  
    public string Title { get; set; } 
    public string Preamble { get; set; } 
    public string Body { get; set; } 
    public DateTime Created { get; set; } 

    public int UserId { get; set; } 

    public virtual User User { get; set; } 

    public int CategoryId { get; set; } 
    public int ImageId { get; set; } 

    public virtual Image Image { get; set; } 
    public virtual Category Category { get; set; } 
} 

public class Image 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string ImageUrl { get; set; } 
    public Byte[] ImageData { get; set; } 
    public string ImageMimeType { get; set; } 
} 

public class Category 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

.... seguenti modelli (questi modelli sono collegati al EfDbContext) collegato al seguente repository ...

Interfaccia/repository

public class NewsRepository : INewsRepository 
{ 
    EfDbContext context = new EfDbContext(); 

    public IQueryable<News> All 
    { 
     get { return context.News; } 
    } 

    public IQueryable<News> AllIncluding(params Expression<Func<News, object>>[] includeProperties) 
    { 
     IQueryable<News> query = context.News; 
     foreach (var includeProperty in includeProperties) { 
      query = query.Include(includeProperty); 
     } 
     return query; 
    } 

    public News Find(int id) 
    { 
     return context.News.Find(id); 
    } 

    public void InsertOrUpdate(News news) 
    { 
     if (news.Id == default(int)) { 
      // New entity 
      context.News.Add(news); 
     } else { 
      // Existing entity 
      context.Entry(news).State = EntityState.Modified; 
     } 
    } 

    public void Delete(int id) 
    { 
     var news = context.News.Find(id); 
     context.News.Remove(news); 
    } 

    public void Save() 
    { 
     context.SaveChanges(); 
    } 
} 

public interface INewsRepository 
{ 
    IQueryable<News> All { get; } 
    IQueryable<News> AllIncluding(params Expression<Func<News, object>>[] includeProperties); 
    News Find(int id); 
    void InsertOrUpdate(News news); 
    void Delete(int id); 
    void Save(); 
} 

Nel mio HomeController() ho ottenuto un metodo JsonResult che voglio restituire il contesto. Ecco il metodo

JSON Richiesta

[HttpGet] 
    public JsonResult GetNews() 
    { 
     var p = newsRepository.AllIncluding(news => news.Category, news => news.Image); 
     return Json(p, JsonRequestBehavior.AllowGet); 
    } 

ottengo il seguente errore:

stato rilevato un riferimento circolare mentre la serializzazione di un oggetto di tipo System.Data.Entity.DynamicProxies' .News_96C0B16EC4AC46070505EEC7537EF3C68EE6CE5FC3C7D8EBB793B2CF9BD391B3' .

ho intuito che questo ha qualcosa a che fare con la roba lazyloading (Iam attualmente apprendimento su C#) ho trovato questo articolo su questo ...

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

ma mi hanno dato per funzionare. .. quello che ho potuto leggere sul codice era che stavano cercando di approfondire la ricerca attraverso l'oggetto ... più di quello che non riuscivo a capire.

la mia domanda è come posso passare in oggetti lazyLoading? in json/serializer o non esiste, qualche pensiero su come posso procedere?

risposta

12

Poiché Json è un formato di serializzazione ad albero, presenta problemi con riferimenti come A-> B-> A.
Ho letto da qualche parte che è possibile utilizzare l'attributo in viewmodels per evitare questo errore. Ma non l'ho provato.

È possibile modificare il codice per le (tipi anonimi di utilizzo) segue per recuperare gli elementi con successo:

var p = newsRepository.AllIncluding(news => news.Category, news => news.Image) 
    .Select(n => new {id = n.Id, Body = n.Body}); 

Includere qualsiasi altra proprietà che si desidera visualizzare nel l'ultimo metodo Select. Ciò rende anche i tuoi risultati Json più leggeri.

+0

grazie per la risposta !, sì ho risolto come hai fatto tu, ma volevo usare la dinamica (lazyloading), per ottenere il risultato JSON dal suo lavoro non prezioso per ricreare il modello nel controller, questo è quello che penso ... beh proverò se ScriptIgnore funziona .. grazie! – Martea

+0

@Martea: Nessun problema. Se pensi che questa sia la risposta alla tua domanda, contrassegnala come risposta. – Kamyar

6

Per aggiungere alla risposta di Kamyar ...

Il metodo AllIncluding è disponibile solo se si sta utilizzando MVC ponteggi. vedere il seguente collegamento per un elenco del metodo: Mvc 3 Scaffolding: the Model passed to the View throws SQL errror

Ho provato ad utilizzare, ma ancora incontrato l'errore di riferimento circolare, poiché gli oggetti radice venivano ancora restituiti come proxy. Quindi ho personalizzato il metodo per disattivare temporaneamente il flag ProxyCreationEnabled nel contesto EF e caricare avidamente le proprietà specificate elencate nel parametro del metodo.Vedere il seguente link per ulteriori dettagli: Loading from database without proxy classes?

Al fine di questo lavoro, la query doveva essere eseguita mentre l'ambiente era ancora fuori, così ho dovuto chiamare il metodo ToList() della query per eseguire la query, e quindi restituito l'oggetto IEnumerable, anziché IQueryable. Questo ha fatto il lavoro per me.

Qui è il metodo che ho usato ("_context" è il nome della variabile per il mio contesto EF):

public IEnumerable<TEntity> ListIncluding<TEntity>(params Expression<Func<TEntity, object>>[] includeProperties) 
    where TEntity : class 
{ 
    bool cachedSetting = _context.Configuration.ProxyCreationEnabled; 
    _context.Configuration.ProxyCreationEnabled = false; 

    IQueryable<TEntity> query = _context.Set<TEntity>(); 
    foreach (var includeProperty in includeProperties) 
    { 
     query = query.Include(includeProperty); 
    } 
    IEnumerable<TEntity> list = query.ToList(); 
    _context.Configuration.ProxyCreationEnabled = cachedSetting; 

    return list; 
} 

Questo può quindi ottenere chiamato utilizzando la seguente sintassi:

IEnumerable<News> newsItems = newsRepository.ListIncluding<News>(news => news.Category, news => news.Image); 
Problemi correlati