如何解决查询列表中的单个项目
问题
我想在我的详细信息页面上显示一只宠物。我无法理解如何编写 LINQ(方法语法)以从数据库中提取单个宠物/物品。
我目前的理解
在使用 LINQ 时,它的闪亮目的是能够遍历数据库中的 IEnumerable
数组或列表。当您查看我的 HomeController
时,我非常有信心我有正确的代码段来构建我想要的 MINUS 查询。
请求
HomeController.cs
[HttpGet("pet/{PetId}")]
public IActionResult Detail(Pet singlePet)
{
List<Pet> Animal = _context.Pets
//***MISSING QUERY CODE HERE***
return View("Pet",singlePet);
}
Details.cshtml
@model Petviewmodel
<div>
<h1>Pet Shelter</h1>
@foreach (Pet creature in Model.Pets)
{
<h3>Details about: @creature.Name</h3>
<div>
<p>Pet Type: @creature.Type</p>
<p>Description: @creature.Description</p>
<p>Skill One:@creature.Skill1</p>
<p>Skill Two:@creature.Skill2</p>
<p>Skill Three:@creature.Skill3</p>
</div>
}
</div>
Petviewmodel.cs
using System.Collections.Generic;
namespace petShelter.Models
{
public class Petviewmodel
{
public Pet Animal { get; set; }
public List<Pet> Pets { get; set; }
public List<Owner> Owners { get; set; }
public Owner Owner { get; set; }
}
}
Pet.cs
using System;
using System.ComponentModel.DataAnnotations;
namespace petShelter.Models
{
public class Pet
{
[Key]
public int PetId { get; set; }
[required]
public string Name { get; set; }
[required]
public string Type { get; set; }
[required]
public string Description { get; set; }
public string Skill1 { get; set; }
public string Skill2 { get; set; }
public string Skill3 { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public Owner Owner { get; set; }
public int? OwnerId { get; set; }
}
}
解决方法
短版
使用
var singlePet=_context.Pets.Find(someId);
或
var singlePet=_context.Pets.FirstOrDefault(x=>x.PetId=someId);
说明
LINQ 查询不查询列表。它们由 LINQ 提供程序转换为目标数据存储理解的任何内容。查询数据库时,它们会被转换为 SQL。
List<Pet> Animal = _context.Pets
不会编译,这是一件非常好的事情 - 如果编译通过,它会将整个表加载到内存中,而不是查询它。过滤将在客户端执行,没有索引的好处。由于浪费了 IO、浪费了 RAM,性能将比简单的 SQL 查询差数量级,更糟糕的是,在只需要一个表时就锁定表中的每一行。过多的锁会导致其他尝试使用同一张表的请求出现延迟。
Pets
是 DbSet<T>
,而不是 List<T>
。它不是一个容器,它代表一个实体,本身不保存任何数据。它可用于编写转换为 SQL 的查询。
假设 PetId
是 Pet
的主键,加载单个记录的最简单和最快的方法是调用 DbSet.Find。此方法使用提供的主键值检索对象。
这个查询:
var singlePet=_context.Pets.Find(someId);
翻译为
select ...
from Pets
where PetID=@id
这将在 DbContext 中加载并缓存一个 Pet 实例。之后,每次在同一个请求中使用相同的 PK 值调用 Find
时,都会返回缓存的对象。
查询
var singlePet=_context.Pets.FirstOrDefault(x=>x.PetId=someId);
将翻译成
select top 1 ...
from Pets
where PetID=@id
在这种情况下没有缓存任何东西。
,如果你不关心,只想从数据库中得到一个结果,你可以做这样的事情
var singlePet = _context.Pets.First();
如果你想要第一个匹配表达式的结果,你可以这样做
var singlePet = _context.Pets.First( e => e.Id == '1');
如果你只期待一个与表达式匹配的结果,你可以做这样的事情
var singlePet = _context.Pets.Single( e => e.PetId == '1' );
,
如果你只想要一个,根本没有过滤器,你可以使用它,它会让你成为列表中的第一个:
var aSpecificPet = Pets.FirstOrDefault();
如果您需要指定某种条件来确定要携带哪种宠物,您可以使用以下内容:
var aMoreSpecificPet = Pets.FirstOrDefault(x=>x.Type == "Dog");
请记住,您作为条件传递的任何内容都将过滤宠物列表,而使用 FirstOrDefault,您将获得第一个(如果有)符合您的条件的宠物。
此外,默认值通常为空(以防没有宠物符合您的条件),因此最好始终添加像
这样的行if(pet != null){
your code
}
如果您想要所有符合该条件的宠物,请使用:
var allDogsInPets = Pets.Where(x=>x.Type == "Dog").ToList();
.ToList() 返回一个包含符合您条件的宠物的新列表。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。