0

问题

我想在我的详细信息页面上显示一只宠物。我无法理解如何编写 LINQ(Method Syntax) 从数据库中提取单个宠物/物品。

到目前为止我的理解

使用 LINQ 时,它的闪亮目的是能够遍历IEnumerable数据库中的数组或列表。当您查看我HomeController的 .

要求

使用方法语法,我应该使用什么查询来拉单个宠物?

家庭控制器.cs

[HttpGet("pet/{PetId}")]
public IActionResult Detail(Pet singlePet)
{
        List<Pet> Animal = _context.Pets
        //***MISSING QUERY CODE HERE***

        return View("Pet", singlePet);
}

详细信息.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; }
    }
}

宠物.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; }

    }
}
4

3 回答 3

3

精简版

利用

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 实例。之后,每次Find在同一个请求中调用相同的PK值,都会返回缓存的对象。

查询

var singlePet=_context.Pets.FirstOrDefault(x=>x.PetId=someId);

将翻译为

select top 1 ... 
from Pets 
where PetID=@id

在这种情况下没有缓存任何内容。

于 2021-05-19T05:23:39.623 回答
2

如果您不在乎,只想从数据库中获取单个结果,则可以执行以下操作

var singlePet = _context.Pets.First();

如果您想要与表达式匹配的第一个结果,您可以执行以下操作

var singlePet = _context.Pets.First( e => e.Id == '1');

如果您只期望一个与表达式匹配的结果,您可以执行以下操作

var singlePet = _context.Pets.Single( e => e.PetId == '1' );
于 2021-05-19T04:52:52.957 回答
0

如果你只想要一个,根本没有过滤器,你可以使用它,它会让你成为列表中的第一个:

var aSpecificPet = Pets.FirstOrDefault();

如果您需要指定某种条件来确定要带哪个宠物,您可以使用类似的东西:

var aMoreSpecificPet = Pets.FirstOrDefault(x=>x.Type == "Dog");

请记住,您作为条件传递的任何内容都将过滤 Pets 列表,并且使用 FirstOrDefault 您将获得第一个(如果有的话)符合您的条件的宠物。

此外,默认值通常为 null(如果没有宠物符合您的条件),因此最好始终添加一行

if(pet != null){
  your code
}

如果您想要所有符合该条件的宠物,请使用:

var allDogsInPets = Pets.Where(x=>x.Type == "Dog").ToList();

.ToList() 返回一个新列表,其中包含符合您的条件的宠物。

于 2021-05-19T04:56:56.503 回答