.NET Core多对多关联表操作触发栈溢出及访问冲突异常求助
解决多对多关联时的Stack Overflow与Access Violation异常
问题概述
每次尝试关联多对多关系的相关表时,程序触发**Stack Overflow(栈溢出)和Access Violation(访问冲突)**异常,尽管数据已成功插入数据库,但程序仍会崩溃。
错误日志摘要
调试控制台输出:
info: Microsoft.Hosting.Lifetime[0] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: C:\Users\vynar\source\repos\IndividualProjects\E_Library\API Stack overflow. C:\Users\vynar\source\repos\IndividualProjects\E_Library\API\bin\Debug\netcoreapp3.1\ELibrary.API.exe (process 14384) exited with code -1073741819.
VS输出窗口关键信息:
The program '[14384] ELibrary.API.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.
问题根源
从你的代码来看,问题出在序列化循环引用上:
- 你在
Attach方法中,给book.AuthorBooks和author.AuthorBooks都添加了authorBook实例 - 当控制器通过
CreatedAtAction返回authorBook时,JSON序列化器会尝试序列化整个对象图:AuthorBook包含Book和Author引用Book又包含AuthorBooks集合,其中又包含当前的AuthorBookAuthor同理也包含AuthorBooks集合,形成无限递归
- 这种无限递归会不断消耗栈内存,最终导致栈溢出和访问冲突
解决方案
方案1:使用DTO(数据传输对象)避免循环引用
不要直接返回实体类AuthorBook,而是创建一个专门的DTO类,只包含需要返回的字段:
// 定义DTO类 public class AuthorBookDto { public int BookId { get; set; } public int AuthorId { get; set; } // 可以按需添加其他需要返回的字段,比如书名、作者名等 }
然后修改Service和Controller的返回逻辑:
Service层修改:
public async Task<AuthorBookDto> Attach(int bookId, int authorId) { var book = await _unitOfWork.Books.GetByIdAsync(bookId); var author = await _unitOfWork.Authors.GetByIdAsync(authorId); // 修正判断逻辑:只要其中一个不存在就返回null if (book == null || author == null) { return null; } var authorBook = new AuthorBook() { AuthorId = author.Id, BookId = book.Id }; book.AuthorBooks.Add(authorBook); author.AuthorBooks.Add(authorBook); await _unitOfWork.CommitAsync(); // 转换为DTO返回 return new AuthorBookDto { BookId = authorBook.BookId, AuthorId = authorBook.AuthorId }; }
Controller层修改:
[Authorize(Roles = "Admin, Manager")] [HttpPost("attach")] public async Task<IActionResult> Attach([FromBody] AuthorBookModel authorBook) { var createdLink = await _service.Attach(authorBook.BookId, authorBook.AuthorId); if (createdLink == null) { return BadRequest(authorBook); } return CreatedAtAction(nameof(GetAllBooks), createdLink); }
方案2:配置JSON序列化器忽略循环引用
如果你坚持要返回实体类,可以在Startup.cs中配置JSON序列化器忽略循环引用:
// 在ConfigureServices方法中添加 services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; });
注意:.NET Core 3.1默认使用System.Text.Json,使用NewtonsoftJson需要先安装
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet包
方案3:在实体类中标记忽略序列化的导航属性
可以通过[JsonIgnore]特性标记不需要序列化的导航属性,避免循环引用:
public class Book { // 其他属性... [JsonIgnore] public ICollection<AuthorBook> AuthorBooks { get; set; } } public class Author { // 其他属性... [JsonIgnore] public ICollection<AuthorBook> AuthorBooks { get; set; } }
额外提示
你Service层中的原判断逻辑if (book == null && author == null)存在逻辑错误,应该改为if (book == null || author == null)——只要书籍或作者其中一个不存在,就不应该创建关联,而不是两个都不存在才返回null。
内容的提问来源于stack exchange,提问作者Nazar Vynar
相关产品推荐
相关产品推荐

