2011-09-30 5 views
7

więc heres sprawa mamEntityFramework do obejścia Json? (Okrągła Wniosek ten został wykryty podczas szeregowania obiektu typu ... DynamicProxies)

modele

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

.... następujących modelach (modele te są połączone do EfDbContext) połączony z następnym repozytorium ...

interfejsu/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(); 
} 

W moim HomeController() mam metodę JsonResult, którą chcę zwrócić kontekst. Oto Metoda

Json Zapytanie

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

pojawia się następujący błąd:

Cykliczne Wniosek ten został wykryty podczas szeregowania obiektu typu System.Data.Entity.DynamicProxies” .News_96C0B16EC4AC46070505EEC7537EF3C68EE6CE5FC3C7D8EBB793B2CF9BD391B3 '.

Domyśliłem się, że to ma coś wspólnego z rzeczy lazyloading (IAM obecnie nauki o języku C#) Znalazłem ten artykuł na ten temat ...

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

ale nie zrobił i zmusić go do pracy. ... o kodzie mogłem przeczytać, że próbowali głębiej przeszukiwać obiekt ... o wiele więcej nie mogłem wymyślić.

Moje pytanie brzmi: jak mogę przekazać obiekty LazyLoading? do json/serializer lub nie istnieje, żadnych myśli, w jaki sposób mogę kontynuować?

Odpowiedz

12

Ponieważ Json jest formatem serializacji opartym na drzewach, ma problemy z odniesieniami, takimi jak A-> B-> A.
Czytałem gdzieś, że możesz użyć atrybutu w swoich modelach, aby zapobiec temu błędowi. Ale nie testowałem tego.

Można zmienić swój kod do następujących (w ruchu anonimowych typów), aby odzyskać elementy z powodzeniem:

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

zawierać dowolny inny obiekt, który ma być wyświetlany w ostatnim Select metody. To sprawia, że ​​Twoje wyniki w Json są również bardziej lekkie.

+0

Dzięki za odpowiedzi na !, tak rozwiązałem to tak, jak zrobiłeś, ale chciałem użyć dynamicznego (lazyloading), aby uzyskać wynik json od czasu, gdy jego niepotrzebna praca odtworzenia modelu w kontrolerze, to co myślę ... cóż, spróbuję jeśli ScriptIgnore działa ... dzięki! – Martea

+0

@Martea: Nie ma problemu. Jeśli uważasz, że jest to odpowiedź na twoje pytanie, oznacz to jako odpowiedź. – Kamyar

6

Aby dodać odpowiedź Kamyar za ...

Sposób AllIncluding jest dostępna tylko wtedy, gdy używasz MVC rusztowania. zobacz poniższy link, aby wyświetlić listę metod: Mvc 3 Scaffolding: the Model passed to the View throws SQL errror

Próbowałem go używać, ale nadal napotkał błąd odwołania cyklicznego, ponieważ obiekty root były nadal zwracane jako proxy. Dlatego dostosowałem metodę tak, aby tymczasowo wyłączyć flagę ProxyCreationEnabled w kontekście EF i chciałem załadować określone właściwości wymienione w parametrze metody.Patrz na poniższy link w celu uzyskania dalszych informacji: Loading from database without proxy classes?

Aby to zadziałało, zapytanie musiały być wykonywane przy ustawieniu nadal wyłączone, więc musiałem zadzwonić metodę kwerendy za ToList(), aby wykonać zapytanie, a następnie zwrócił wartość IEnumerable, a nie IQueryable. To zrobiło to za mnie.

Oto metoda użyłem („_context” to nazwa zmiennej dla mojego kontekście 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; 
} 

Można wówczas uzyskać nazywane przy użyciu następującej składni:

IEnumerable<News> newsItems = newsRepository.ListIncluding<News>(news => news.Category, news => news.Image); 
Powiązane problemy