0

我的 Web API 2 项目中有一个简单的 GET 方法,它通过始终返回错误的实体框架查询我的 Microsof tSQL 数据库。如果我在调试器中单步执行它,则不会遇到异常。它实际上看起来像是干净地离开了方法。我很困惑。

    [Route("ar")]
    public IHttpActionResult GetAuditArs(int auditId)
    {
        using (var context = new LabSOREntities()) {
            try {
                var ars = from r in context.SMBWA_Audit_AR
                          where r.SMBWA_Audit_Id == auditId
                          select r;

                var ret = Ok(ars.ToArray());

                return ret;
            } catch (Exception ex) {
                return BadRequest($"Something went wrong: {ex.Message}");
            }
        }
    }

数据库中有一行,我看到我ars.ToArray()的说法是其中有一个元素。我该如何调试它,因为它在爆炸时离开了我的方法?

如果我只是通过浏览器点击那个端点,我会得到:

<Error>
<Message>发生错误。</Message>
</Error>

4

1 回答 1

1

问题将是您从 API 调用返回实体。在幕后,WebAPI 必须序列化返回的数据,因为它会命中任何延迟加载引用属性并尝试加载它们。由于您在 using 块中实例化范围内的 DB 上下文,因此实体将在序列化之前从上下文中孤立出来,因此 EF 将抛出 DB 上下文不可用的异常。

验证行为的选项 - 急切加载“SMBWA_Audit_AR”类中的所有引用。这应该消除错误并确认延迟加载序列化问题。

var ars = context.SMBWA_Audit_AR
    .Include(x => x.Reference1)
    .Include(x => x.Reference2) // etc. where Reference1/2 are related entites to your audit record. If you have a lot of references, that is a lot of includes...
    .Where(x => x.SMBWA_Audit_Id = auditId)
    .ToArray();

为了避免这样的问题,以及急切加载所有内容的成本/时间,我建议使用 POCO DTO/ViewModel 返回有关这些审计记录的详细信息。然后您可以 .Select() POCO 所需的字段。这避免了延迟加载序列化问题,并优化了来自 EF 的查询以仅返回所需的数据,而不是整个对象图。

例如:如果您需要在审核摘要列表中显示审核编号、名称和备注字段:

public class AuditSummary
{
  public int AuditID {get; set;}
  public string AuditorName {get; set;}
  public string Notes {get; set;}
  // You can add whatever fields are needed from the Audit or related entities... Including collections of other DTOs for related entites, or summary details like Counts etc..
}

var ars = context.SMBWA_Audit_AR
    .Where(x => x.SMBWA_Audit_Id = auditId)
    .Select(x => new AuditSummary 
       {
         AuditId = x.AuditId,
         AuditorName = x.AuditedBy.Name, //Example getting reference details..
         Notes = x.Notes
       }).ToArray();

反映消费者需求的退货模型。这避免了 EF 的问题并确保您的查询高效。

  • 使用 IoC 容器(Unity/Autofac 等)将 DbContext 范围限定为请求。这似乎是一个可行的选择,但不建议这样做。虽然它会避免错误,但当序列化程序迭代您的实体时,您的 DbContext 将按 ID 一次查询每个单独的依赖项。您可以通过在应用程序运行时对数据库运行分析器来检测延迟加载调用来查看此行为。它最终会起作用,但它会很慢。

作为一般规则,不要从 Web API 或 MVC 控制器方法返回实体,以避免序列化程序出现错误和性能问题。

于 2018-05-11T00:55:53.113 回答