EntityFramework для обхода JSON? (При сериализации объекта типа...DynamicProxies была обнаружена циклическая ссылка) [дубликат]

этот вопрос уже есть ответ здесь:

Итак, вот сделка, которую я имею

модели

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

....следующие модели (эти модели подключены к EfDbContext) подключены к следующему хранилище...

Интерфейс/Репозиторий

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

в моем HomeController () я получил метод jsonresult, который я хочу вернуть контекст. Вот метод

Запрос Json

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

Я получаю следующую ошибку:

при сериализации объекта типа обнаружена круговая ссылка - Система.Данные.Сущность.DynamicProxies.News_96C0B16EC4AC46070505EEC7537ef3c68ee6ce5fc3c7d8ebb793b2cf9bd391b3'.

Я догадался, что это имеет какое-то отношение к lazyloading(IAM в настоящее время изучает C#), я нашел эту статью об этом...

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

но я не смог заставить его работать... что я мог прочитать о коде, так это то, что они были tryin для поиска глубины через объект... больше я ничего не мог понять.

мой вопрос в том, как я могу передать в lazyLoading объекты? в JSON/сериализатор или его не существует, никаких мыслей о том, как я могу действовать?

2 ответов


поскольку Json-это формат сериализации на основе дерева, у него есть проблемы со ссылками, такими как A->B->A.
Я где-то читал, что вы можете использовать ScriptIgnore атрибут в viewmodels, чтобы предотвратить эту ошибку. Но не проверяли его.

для успешного извлечения элементов можно изменить код на следующий (использовать анонимные типы):

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

включить любое другое свойство, которое вы хотите отобразить в последнем Select метод. Это делает Результаты Json также более легкие.


добавить в ответ Kamyar по...

метод AllIncluding доступен только при использовании лесов MVC. смотрите по ссылке список способ: MVC 3 леса: Модель, переданная в представление бросает SQL errror

Я попытался использовать его, но все еще столкнулся с ошибкой круговой ссылки, так как корневые объекты все еще возвращались как прокси. Поэтому я настроил метод, чтобы временно отключить флаг ProxyCreationEnabled на контекст EF и с нетерпением загружает указанные свойства, перечисленные в параметре метода. Дополнительные сведения см. по следующей ссылке: загрузка из базы данных без прокси-классы?

чтобы это работало, запрос должен был выполняться, пока параметр все еще был выключен, поэтому мне пришлось вызвать метод toList() запроса для выполнения запроса, а затем вернуть IEnumerable, а не IQueryable. Это сделало работу за меня.

вот метод, который я использовала ("_context" - это имя переменной для моего контекста 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;
} 

Это может быть вызвано с помощью следующего синтаксиса:

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