EntityFramework到Json的解决方法?(序列化类型的对象时检测到循环引用... DynamicProxies)

Mar*_*tea 7 asp.net-mvc json entity-framework

所以我有这笔交易

楷模

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; }
}
Run Code Online (Sandbox Code Playgroud)

....以下模型(这些模型连接到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();
}
Run Code Online (Sandbox Code Playgroud)

在我的HomeController()中,我得到了一个JsonResult metod,我想返回上下文.这是方法

Json请求

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

我收到以下错误:

序列化"System.Data.Entity.DynamicProxies.News_96C0B16EC4AC46070505EEC7537EF3C68EE6CE5FC3C7D8EBB793B2CF9BD391B3"类型的对象时检测到循环引用.

我猜这与懒加载的东西有关(Iam目前正在学习C#)我发现这篇文章关于这个......

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

但我没有得到它的工作...我能读到的关于代码的是他们试图通过对象深入搜索...比我想不到的更多.

我的问题是如何传递lazyLoading对象?进入json/serializer还是不存在,对我如何进行的任何想法?

Kam*_*yar 12

由于Json是基于树的序列化格式,因此它存在诸如A-> B-> A之类的引用的问题.
我在某处读过你可以在viewmodels中使用ScriptIgnore属性来防止这个错误.但还没有测试过.

您可以将代码更改为以下(使用匿名类型)以成功检索项目:

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

包括您希望在最后一个Select方法中显示的任何其他属性.这使得您的Json结果也更加轻量级.


And*_*mas 6

添加到Kamyar的答案......

只有在使用MVC脚手架时,AllIncluding方法才可用.请参阅以下链接以获取该方法的列表: Mvc 3 Scaffolding:传递给View的模型抛出SQL错误

我尝试使用它,但仍然遇到循环引用错误,因为根对象仍然作为代理返回.所以我定制了方法来暂时关闭EF上下文中的ProxyCreationEnabled标志,并急切地加载方法参数中列出的指定属性.有关更多详细信息,请参阅以下链接: 从没有代理类的数据库加载?

为了使其工作,必须在设置仍然关闭时执行查询,因此我不得不调用查询的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;
} 
Run Code Online (Sandbox Code Playgroud)

然后可以使用以下语法调用它:

IEnumerable<News> newsItems = newsRepository.ListIncluding<News>(news => news.Category, news => news.Image); 
Run Code Online (Sandbox Code Playgroud)