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

C# 如何根据多个条件使用Linq查找特定项目?,c#,asp.net-mvc,linq,asp.net-identity,C#,Asp.net Mvc,Linq,Asp.net Identity,我有一个非常简单的问题: //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.ApplicationUs

我有一个非常简单的问题:

//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; }
}
ApplicationUser
拥有
监视产品的列表


我的问题是,为什么我没有得到
WatchedProduct产品
我得到了一个
IQueryable产品

这是因为你使用了
Where()方法
Where()
方法根据lambda表达式过滤数据
=>u.applicationserid==user.Id&&u.ProductId==Id
,并返回
IQueryable
IEnumerable
(请参阅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));
这将返回一个项目,如果没有找到,则返回null。注意:如果找到多个项目,它将抛出异常,但它不应该这样做,因为产品id很可能是唯一的,如果它找到的项目越多,您就会知道您的数据库中有多个相同id的产品

如果可以接受该查询可以有多个记录作为结果,则使用
FirstOrDefault
而不是
SingleOrDefault
,但这样的逻辑就不太正确了,因为让一个需要返回一个或不返回的查询返回列表中的第一个查询是没有意义的

这是因为
Where
扩展方法返回
IEnumerable
。对于db set,它返回
IQueryable
,即
IEnumerable

在您的情况下,由于您使用的是异步/等待模式,因此可以使用
FirstOrDefaultAsync
获取单个项目作为结果:

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

linq返回一个IQueryable,这样您就可以继续在末尾追加额外的linq调用。这是理想的。如果你想要一个可枚举的或其他的,你可以做一个可计算的()除非你调用
ToList
First
或类似的方法,否则你不会得到一个列表或对象。在调用之前,对象仍然是一个“查询”。使用
wait Task.Run()
没有任何意义。我在ASP MVC中不是最好的,但我在HTTP请求(webapi)中使用该查询,所以我添加了该任务运行。我不知道为什么有人在没有投票的情况下否决了我的问题explenation@michasaucer我共享
FirstOrDefaultAsync
的原因是,当您使用类似
FirstOrDefaultAsync
的异步方法时,不应使用
Task.Run(),但是我认为您不需要以异步方式运行linq语句,因此您可以跳过“wait Task.run”,如下所示:
var product=db.WatchedProducts.Where(u=>u.applicationserid==user.Id&&u.ProductId==Id.FirstOrDefault()并且它与延迟执行没有任何关系。这是因为
Where
返回
IEnumerable
为什么不
FirstOrDefault
而不是
Where
?@右上一步,实际上它取决于通过扩展方法扩展的类型。在
DbSet
的情况下,它返回
IQueryable
,实际上它是
IEnumerable
。谢谢你的评论:)