![](/img/trans.png)
[英]System.Text.Json.JsonException: 'A possible object cycle was detected which is not supported....'
[英]System.Text.Json.JsonException: A possible object cycle was detected
我正在開發一個.Net 博客風格 API 作為一個練習項目,並且遇到了這個錯誤。 我有一個用戶 class,發布 class 和評論 class。 Comment 引用 Post 和 User,每個都是一對多的。
這是我的用戶 class:
public class User
{
//Other properties..
public List<Post> Posts { get; set; }
public List<Comment> Comments { get; set; }
}
我的帖子 class:
public class Post
{
//Other properties..
public List<Comment> Comments { get; set; }
[Required]
public User CreatedBy { get; set; }
}
和我的評論 class:
public class Comment
{
//Other properties..
[Required]
public User CreatedBy { get; set; }
[Required]
public Post Post { get; set; }
}
我正在嘗試保存這樣的評論(我從以前的方法中填充了 Post.Id 和 CreatedBy.Id)。 這就像它按預期插入數據庫一樣工作,但是我得到了 JsonException。
comment.Post = await _context.Posts.SingleOrDefaultAsync(p => p.Id == comment.Post.Id);
comment.CreatedBy = await _context.Users.FindAsync(comment.CreatedBy.Id);
await _context.Comments.AddAsync(comment);
await _context.SaveChangesAsync();
return comment;
我可以通過添加 Microsoft.AspNetCore.Mvc.NewtonsoftJson 並將其添加到我的啟動 class 來解決這個問題
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
但我想知道我是否應該在我的代碼中做些什么來避免這種情況,而不是僅僅提供一個選項來說明它沒關系。
Post 的一個實例包含一個 Comments 列表。 每個評論實例都包含一個帖子。 Post 的一個實例包含一個 Comments 列表。 每個 Comment 實例都包含一個 Post.... 等等。
雖然這樣做並不違反 C# 的規則,但我更願意避免這樣做,因為它會給數據集合帶來未知的復雜性。 文本序列化是您在執行此操作時會遇到的最大痛點之一。 盡管有一些方法可以處理這些痛點(ReferenceLoopHandling 和 Ignore 屬性標簽等等),但我發現從我的 class 定義中盡可能多地省略引用循環要容易得多,即使這意味着定義兩個不同命名的類相同的屬性,例如 Comment 和 PostComment(其中 PostComment 將是包含在帖子下的評論)。
例如,像下面這樣的結構會破壞循環引用,並使其易於序列化並持久化到數據庫中。 注意 Post 的 Comment 屬性的類型更改以及 PostComment 中相關的 Post 省略,從而打破了循環。
public class User
{
//Other properties..
public List<Post> Posts { get; set; }
public List<Comment> Comments { get; set; }
}
public class Post
{
//Other properties..
public List<PostComment> Comments { get; set; }
[Required]
public User CreatedBy { get; set; }
}
public class Comment
{
//Other properties..
[Required]
public User CreatedBy { get; set; }
[Required]
public Post Post { get; set; }
}
public class PostComment
{
//Other properties..
[Required]
public User CreatedBy { get; set; }
}
我的 api (.net 5) 也有類似的問題。 拋出的異常 500 無法被 API 捕獲。 要查看實際問題,我必須從 go 到 windows “事件記錄器”。
為了解決我在配置(startup.cs)中添加的問題:
services.AddMvc()
.AddJsonOptions(opt =>
{
opt.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
});
為避免循環,您可以嘗試使用急切加載並添加IgnoreAutoIncludes()
擴展方法。 通過使用Include()
擴展方法的這種方式,您可以指定要使用查詢拉回的導航屬性(但在您的特定情況下,您不需要包含任何內容,因為您只對 Post 實體感興趣):
comment.Post = await _context.Posts.IgnoreAutoIncludes()
.SingleOrDefaultAsync(p => p.Id == comment.Post.Id);
此外,如果您使用的是 Fluent API,您可以通過在OnModelCreating()
方法中添加Ignore
從映射中排除屬性:
modelBuilder.Entity<Post>().Ignore(c => c.Comments);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.