控制器返回一个数据列表而不是单个项目,如何解决这个问题?
背景控制器返回一个数据列表而不是单个项目,如何解决这个问题?
最近我改变了工作,并附加到一个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
我试图从邮差相同的呼叫,这就是输出。请注意,我更改了有问题的请求,控制器代码等以省略一些私人详细信息。
我可以看到,响应包含我所需要的数据,但所有的关系的另一端内的数据一起。如果我没有弄错,默认情况下,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; }
}
当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();
这解决了我的问题。谢谢! – raidensan
如果您使用实体框架的Core 2,试试这个:
MyEntityType found = await db.MyEntity.AsNoTracking()
.OrderByDescending(c => c.CreationTime)
.FirstOrDefaultAsync(c => c.ParameterColumn == parameter);
而且最好是包括数据库上下文通过依赖注入,而不是私有字段。
看来,还有你的代码没有被你的要求击中。检查另一个类似的函数,返回整个列表并将其包含在你的问题中。 –
您可以在您的问题中发帖,您是如何调用此方法的?我没有看到你发布的内容,你如何获得返回的列表。 –
是的,这一切对我来说都很好。我们能否看到客户端如何调用您的API? – DarthJam