引起循环引用的对象序列化

时间:2015-11-19 08:02:58

标签: c# asp.net-mvc entity-framework asp.net-identity

我有一个简单的文章类:

   public class Article
   {
    [Key]
    public int ArticleId { get; set; }
    public string Title { get; set; }
    public string PageContent { get; set; }
    public System.DateTime PostedDate { get; set; }
    public int? ArticlePostedBy { get; set; }

    public virtual ApplicationUser ApplicationUser { get; set; }
  }

这是我的ApplicationUser类,它与文章类有一对多的关系:

 public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
  {
    public ApplicationUser()
    {
        this.Articles = new HashSet<Article>();
    }
    public virtual ICollection<Article> Articles { get; set; }

我已经使用流畅的api配置了一对多的关系:

    modelBuilder.Entity<Article>()
                   .HasOptional<ApplicationUser>(a => a.ApplicationUser)
                   .WithMany(a => a.Articles)
                   .HasForeignKey(s => s.ArticlePostedBy);

现在,这是我发布文章的控制器:

    [HttpPost]
    public JsonResult Index(Article article)
    {
        article.ArticlePostedBy = User.Identity.GetUserId<int>();
        article.PostedDate = DateTime.UtcNow;
        db.Articles.Add(article);
        db.SaveChanges();
        var usr = db.Users.FirstOrDefault(x => x.Id == article.ArticlePostedBy);
        var ret = new
        {
            Title = article.Title,
            PostedBy = article.ArticlePostedBy,
            PostedByName = usr.UserName,
            PostedByAvatar = db.Users.Include(s => s.Files).SingleOrDefault(s => s.Id == article.ArticlePostedBy),
            PostedDate = article.PostedDate,
            ArticleId = article.ArticleId
        };
        return Json(ret, JsonRequestBehavior.AllowGet);
    }

现在,当我尝试发布数据时出现问题。在提交按钮单击,数据已保存在dbase中,但给出此服务器错误--- 序列化“System.Data.Entity.DynamicProxies.ApplicationUser_04102CD9A296DF3EA26BCA4B5FDF758BC1CD8B55C5601C2EA864BBE5FE4B7F46”类型的对象时检测到循环引用。 现在,我已经阅读了很多关于堆栈溢出的文章,但没有得到任何简单的解决方案。 解决方案是禁用延迟加载,但我无法禁用延迟加载,因为这是我的主要需求。由于这个原因,我的应用程序中的许多函数都会受到影响。有人建议使用ScriptIgnore。 我应该用吗?如果是的话,在哪里申请,或者还有其他更好的方法。我想仅对此特定类应用更改。

1 个答案:

答案 0 :(得分:0)

您的错误正在发生,因为您的returnind(ret)的匿名对象包含PostedByAvatar类型的属性ApplicationUser

ApplicationUser包含ArticleArticle的集合,其中包含ApplicationUser的属性,该属性又包含Article的集合,其中包含ApplicationUser } 等等等等。序列化它会生成循环引用异常。

而不是返回ApplicationUser,只需在视图中返回您需要的ApplicationUser属性。

var user = db.Users.Include(s => s.Files).SingleOrDefault(s => s.Id == article.ArticlePostedBy);

var ret = new
{
    Title = article.Title,
    ....
    PostedByAvatar = user.Files.someProperty;
    ....
}

旁注。您似乎已经由var usr = db.Users.FirstOrDefault(x => x.Id == article.ArticlePostedBy);定义了用户,因此无需再次调用数据库(唯一的区别似乎是.Include()子句,因此应该只包含在var usr = ..中1}}陈述)。