【问题标题】:Controller returns a list of data instead of single item, how to solve this issue?控制器返回数据列表而不是单项,如何解决这个问题?
【发布时间】:2017-09-25 12:10:16
【问题描述】:

背景

最近我换了工作并加入了一个 Web API 项目。我熟悉 Web API 和 MVC 的概念,但之前没有实践经验。

我遵循了一些教程,并基于它们通过 Visual Studio 2017 创建了一个空的 WebApi 项目,从数据库中连接了我的模型并添加了控制器。

这是修改后的控制器:

    private MyEntities db = new MyEntities();
    //...
    [ResponseType(typeof(MyEntityType))]
    [Route("api/MyEntity")]
    public async Task<IHttpActionResult> GetMyEntityType([FromUri]int parameter)
    {
        MyEntityType found = db.MyEntity
            .OrderByDescending(c => c.CreationTime)
            .First(c => c.ParameterColumn == parameter);


        if (found == null)
        {
            return NotFound();
        }

        return Ok(found );
    }

注意:我是根据 KEY 以外的列查询

当我打电话给.../api/MyEntity?parameter=1 时,我希望收到一个回复​​。但是由于我不知道的原因,之前的调用返回了所有项目并且它是未排序的。

请注意:如果我在if (found == null) 上放置断点,我可以确认我的查询产生了单个项目。

问题

我在这里缺少什么?为什么响应包含所有元素而不是单个元素?

更新 1

我尝试了来自 Postman 的相同调用,这是输出。请注意,我已经更改了相关请求、控制器代码等,以省略一些私人细节。

我可以看到响应包含我想要的数据,但还包含关系另一端的所有内部数据。如果我没记错的话,默认情况下,EF 使用延迟加载。由于我没有Include 子句,我不知道为什么所有相​​关数据都会作为响应返回。

我认为我需要调查我在模型/数据库中的关系并确保启用延迟加载。

更新 2

这些是我的实体类:

public partial class MyEntity
{
    public int Id { get; set; }
    public Nullable<int> ForeignKey_ID { get; set; }
    public Nullable<int> MyValue { get; set; }
    public Nullable<System.DateTime> CreationTime { get; set; }
    public Nullable<int> Some_ID { get; set; }

    public virtual MyOtherEntity MyOtherEntity { get; set; }
}

public partial class MyOtherEntity
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public MyOtherEntity()
    {
        this.MyOtherEntity1 = new HashSet<MyOtherEntity>();
    }

    //...

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<MyOtherEntity> MyOtherEntity1 { get; set; }
    public virtual MyOtherEntity MyOtherEntity2 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<MyEntity> MyEntity { get; set; }
}

【问题讨论】:

  • 您显示的代码似乎没有被您的请求命中。检查另一个返回整个列表并将其包含在您的问题中的类似函数。
  • 你能在你的问题中发帖吗,你是如何调用这个方法的?我看不出,根据您发布的内容,您是如何获得返回列表的。
  • 是的,这一切对我来说也很好。我们可以看看客户端是如何调用你的 API 的吗?
  • @KirkLarkin 我在问题中解释过:我可以确认正在使用这种方法。
  • @raidensan 我总是明确地关闭 off 延迟加载,这样无意的枚举就会引发错误,而不是导致返回大量不需要的数据。它使我免于许多潜在的问题,以及必须显式 .Include 导航属性的轻微成本。

标签: c# asp.net-mvc entity-framework asp.net-web-api2


【解决方案1】:

当 MyEntityType 实例通过Ok 返回时,它将被转换为 JSON,该 JSON 将读取所有公共属性和字段的值。这将导致 EF 加载整个实体和所有关系。如果您只需要返回特定属性,请使用 Select(),如下所示。

var found = db.MyEntity
    .OrderByDescending(c => c.CreationTime)
    .Select(c => new { c.CreationTime, c.ParameterColumn })
    .First(c => c.ParameterColumn == parameter);

您可以根据需要定制选定的属性。如果您需要 First() 中不需要选择的条件,请将条件移动到 Select 之前的 Where() 调用中。

var found = db.MyEntity
    .OrderByDescending(c => c.CreationTime)
    .Where(c => c.ParameterColumn == parameter)
    .Select(c => new { c.CreationTime })
    .First();

您可能应该创建一个 MyEntityType 的 ViewModel,它只包含您需要的属性,并将这些属性映射到 ViewModel 的新实例。然后您也可以更新[ResponseType(typeof(MyEntityType))] 属性。

例如,声明:

public class MyEntityTypeViewModel {
    public DateTime CreationTime { get; set; }
    public int ParameterColumn { get; set; }
}

然后在你的控制器动作中:

MyEntityTypeViewModel found = db.MyEntity
    .OrderByDescending(c => c.CreationTime)
    .Where(c => c.ParameterColumn == parameter)
    .Select(c => new MyEntityTypeViewModel { 
        CreationTime = c.CreationTime,
        ParameterColumn = c.ParameterColumn })
    .First();

【讨论】:

    【解决方案2】:

    如果您使用的是 Entity Framework Core 2,请尝试以下操作:

     MyEntityType found = await db.MyEntity.AsNoTracking()
         .OrderByDescending(c => c.CreationTime)
         .FirstOrDefaultAsync(c => c.ParameterColumn == parameter);
    

    最好通过依赖注入包含数据库上下文,而不是私有字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-26
      • 2022-08-23
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多