【发布时间】:2020-03-30 15:32:12
【问题描述】:
我有 2 个实体,它们是一对多相关的
public class Restaurant {
public int RestaurantId {get;set;}
public string Name {get;set;}
public List<Reservation> Reservations {get;set;}
...
}
public class Reservation{
public int ReservationId {get;set;}
public int RestaurantId {get;set;}
public Restaurant Restaurant {get;set;}
}
如果我尝试使用我的 api 预订餐厅
var restaurants = await _dbContext.Restaurants
.AsNoTracking()
.AsQueryable()
.Include(m => m.Reservations).ToListAsync();
.....
我收到错误响应,因为对象包含对彼此的引用。 有相关帖子推荐to create separate model 或添加NewtonsoftJson configuration
问题是我不想创建单独的模型,第二个建议没有帮助。 有没有办法在没有循环关系的情况下加载数据? *
System.Text.Json.JsonException:检测到可能的对象循环 不支持。这可能是由于一个周期或如果 对象深度大于最大允许深度 32。在 System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 最大深度)在 System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions 选项,WriteStack& 状态)在 System.Text.Json.JsonSerializer.WriteAsyncCore(流 utf8Json,对象 值,类型 inputType,JsonSerializerOptions 选项, CancellationToken 取消令牌)在 Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext 上下文,编码选择编码)在 Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext 上下文,编码选择编码)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔值 已完成)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed 上下文)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& 范围, Object& 状态, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
*
【问题讨论】:
-
要求它忽略 Reservation 类的 Restaurant 属性。
-
真的,您不应该直接从您的 API 返回您的数据库实体。我建议创建特定于 API 的 DTO 并相应地映射。当然,您说过您不想这样做,但我认为将 API 和持久性内部分开是一般的好习惯。
-
“问题是我不想创建单独的模型”。除非您这样做,否则您的设计从根本上是有缺陷的。 API 是一个类似于接口的契约(它实际上是一个应用程序编程接口)。一旦发布,它就不应该改变,任何改变都需要一个新版本,新版本需要与旧版本同时运行(将来会被弃用并最终删除)。这让客户有时间更新他们的实现。如果您直接返回一个实体,那么您将紧密耦合您的数据层。
-
对该数据层的任何更改都需要立即且不可逆转地更改 API,立即中断所有客户端,直到它们更新其实现。如果它不明显,那是一件坏事。简而言之:永远不要从 API 接受或返回实体。您应该始终使用 DTO。
-
"您应该始终使用 DTO" ...好吧,不,并非总是如此。如果您的 API 的唯一订阅者是您的 SPA 客户端应用程序 - 如果没有什么可以阻止的,我为什么要浪费时间编写 DTO,因为唯一的订阅者也必须立即更新。最佳做法很好,但我不喜欢“总是”。
标签: c# asp.net-core entity-framework-core