控制器返回一个数据列表而不是单个项目,如何解决这个问题?

问题描述:

背景控制器返回一个数据列表而不是单个项目,如何解决这个问题?

最近我改变了工作,并附加到一个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)上放置断点,我可以确认我的查询导致了单个项目。

问题

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

UPDATE 1

我试图从邮差相同的呼叫,这就是输出。请注意,我更改了有问题的请求,控制器代码等以省略一些私人详细信息。

enter image description here

我可以看到,响应包含我所需要的数据,但所有的关系的另一端内的数据一起。如果我没有弄错,默认情况下,EF使用延迟加载。由于我没有Include条款,我不知道为什么所有的相关数据都是作为回应返回的。

我想我需要调查我在Model/DB中的关系,并确保启用Lazy-Loading。

更新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; } 
} 
+3

看来,还有你的代码没有被你的要求击中。检查另一个类似的函数,返回整个列表并将其包含在你的问题中。 –

+1

您可以在您的问题中发帖,您是如何调用此方法的?我没有看到你发布的内容,你如何获得返回的列表。 –

+0

是的,这一切对我来说都很好。我们能否看到客户端如何调用您的API? – DarthJam

当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的视图模型,而这些映射到视图模型的新实例代替。然后,您也可以更新[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(); 
+0

这解决了我的问题。谢谢! – raidensan

如果您使用实体框架的Core 2,试试这个:

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

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