对象的序列化导致循环引用
serialization of object causing circular reference
我有一篇简单的文章 class 是这样的:
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 class,它与文章 class 具有一对多关系:
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Articles = new HashSet<Article>();
}
public virtual ICollection<Article> Articles { get; set; }
我使用 fluent api 配置了一对多关系,如下所示:
modelBuilder.Entity<Article>()
.HasOptional<ApplicationUser>(a => a.ApplicationUser)
.WithMany(a => a.Articles)
.HasForeignKey(s => s.ArticlePostedBy);
现在,这是我 post 阅读文章的控制器:
[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);
}
现在,当我尝试 post 数据时,问题出现了。单击提交按钮时,数据已保存在数据库中,但会出现此服务器错误---
序列化 'System.Data.Entity.DynamicProxies.ApplicationUser_04102CD9A296DF3EA26BCA4B5FDF758BC1CD8B55C5601C2EA864BBE5FE4B7F46' 类型的对象时检测到循环引用。
现在,我已经阅读了很多关于堆栈溢出的文章,但没有得到任何简单的解决方案。 已提供禁用延迟加载的解决方案,但我无法禁用延迟加载,因为这是我的主要需求。我的应用程序中的许多功能都会因此而受到影响。 某处建议使用 ScriptIgnore。
我应该用那个吗?如果是,在哪里应用它或有任何其他更好的方法。我只想为这个特定的 class.
应用更改
您的错误发生是因为您的 returnind (ret
) 的匿名对象包含 属性 PostedByAvatar
类型 ApplicationUser
.
ApplicationUser
包含 Article
的集合,Article
包含 ApplicationUser
的 属性,后者又包含 Article
的集合其中包含 ApplicationUser
等等。序列化它会产生循环引用异常。
而不是 returning ApplicationUser
,只需 return 视图中需要的 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 = ..
语句中).
我有一篇简单的文章 class 是这样的:
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 class,它与文章 class 具有一对多关系:
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Articles = new HashSet<Article>();
}
public virtual ICollection<Article> Articles { get; set; }
我使用 fluent api 配置了一对多关系,如下所示:
modelBuilder.Entity<Article>()
.HasOptional<ApplicationUser>(a => a.ApplicationUser)
.WithMany(a => a.Articles)
.HasForeignKey(s => s.ArticlePostedBy);
现在,这是我 post 阅读文章的控制器:
[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);
}
现在,当我尝试 post 数据时,问题出现了。单击提交按钮时,数据已保存在数据库中,但会出现此服务器错误--- 序列化 'System.Data.Entity.DynamicProxies.ApplicationUser_04102CD9A296DF3EA26BCA4B5FDF758BC1CD8B55C5601C2EA864BBE5FE4B7F46' 类型的对象时检测到循环引用。 现在,我已经阅读了很多关于堆栈溢出的文章,但没有得到任何简单的解决方案。 已提供禁用延迟加载的解决方案,但我无法禁用延迟加载,因为这是我的主要需求。我的应用程序中的许多功能都会因此而受到影响。 某处建议使用 ScriptIgnore。 我应该用那个吗?如果是,在哪里应用它或有任何其他更好的方法。我只想为这个特定的 class.
应用更改您的错误发生是因为您的 returnind (ret
) 的匿名对象包含 属性 PostedByAvatar
类型 ApplicationUser
.
ApplicationUser
包含 Article
的集合,Article
包含 ApplicationUser
的 属性,后者又包含 Article
的集合其中包含 ApplicationUser
等等。序列化它会产生循环引用异常。
而不是 returning ApplicationUser
,只需 return 视图中需要的 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 = ..
语句中).