如何根据多个条件使用 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; }
}
ApplicationUser
有 WatchedProducts
个列表。
我的问题是,为什么我得到的不是 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)
我有一个非常简单的查询:
//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
有 WatchedProducts
个列表。
我的问题是,为什么我得到的不是 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)