如何根据多个条件使用 Linq 查找特定项目?

How to find specific item with Linq based on multiple conditions?

我有一个非常简单的查询:

//user from UserManager from default AccountController from .net Identity
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

var product = await Task.Run(() 
    => db.WatchedProducts.Where(u => u.ApplicationUserId == user.Id && u.ProductId == id));

我想做的是在 WatchedProducts 列表中找到特定的 product。它的模型如下所示:

public class WatchedProduct
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("ApplicationUser")]
    public string ApplicationUserId { get; set; }
    public virtual ApplicationUser ApplicationUser { get; set; }

    [ForeignKey("Product")]
    public int ProductId { get; set; }
    public virtual Product Product { get; set; }
}

ApplicationUserWatchedProducts 个列表。

我的问题是,为什么我得到的不是 WatchedProduct product,而是 IQueryable<WatchedProduct> product

发生这种情况是因为您正在使用方法 Where()Where() 方法根据您的 lambda 表达式 => u.ApplicationUserId == user.Id && u.ProductId == id 和 returns IQueryable<TSource>IEnumerable<TSource> 过滤您的数据(请参阅 Reza Aghaei 的回答中的精彩解释)。

如果你想获得 WaterProduct 产品,那么只需通过 FirstOrDefault() 方法获得它:

var product = await Task.Run(() 
    => db.WatchedProducts.Where(u => u.ApplicationUserId == user.Id && u.ProductId == id)
       .FirstOrDefault());

您没有获得任何数据,因为您没有具体化您的查询。它被称为延迟执行。延迟执行意味着您的 linq 代码将不会在数据库中执行,直到您需要必要的数据。因此,要具体化数据或在数据库中执行查询,您应该调用如下方法:

foreach, toList(), First(), FirstOrDefault(), Single(), SingleOrDefault(), etc...

你应该使用 SingleOrDefault

据我所知,您的结果应该是唯一的,因为您使用的是唯一的产品 ID

var product = await Task.Run(() 
    => db.SingleOrDefault(u => u.ApplicationUserId == user.Id && u.ProductId == id));

这将 return 一项,如果找到 none 则为空。请注意,如果找到多个项目,它会抛出异常,这是不应该的,因为产品 ID 很可能是唯一的,如果它找到更多的项目,您会知道您在数据库中搞砸了,您有多个产品相同的id

如果该查询的结果可以有不止一条记录是可以接受的,那么使用 FirstOrDefault 而不是 SingleOrDefault 但是这样逻辑就不太正确了,因为查询需要 return 一个或 none 是没有意义的return 列表中的第一个。

因为Where扩展方法returnsIEnumerable<TSource>。在数据库集的情况下,它 returns IQueryable<TSource>IEnumerable<TSource>.

在您的情况下,由于您使用的是 async/await 模式,因此您可以使用 FirstOrDefaultAsync 获得单个项目:

var p = await db.WatchedProducts.FirstOrDefaultAsync(u => u.ApplicationUserId == user.Id &&
                                                          u.ProductId == id)