EntityFramework для обхода JSON? (При сериализации объекта типа...DynamicProxies была обнаружена циклическая ссылка) [дубликат]
этот вопрос уже есть ответ здесь:
- JSON и исключение круговой ссылки 9 ответов
Итак, вот сделка, которую я имею
модели
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);