>我有非常简单的查询:
//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
列表。
我的问题是,为什么我得到IQueryable<WatchedProduct> product
WatchedProduct product
发生这种情况是因为您使用的是方法 Where()
. Where()
方法根据 lambda 表达式=> u.ApplicationUserId == user.Id && u.ProductId == id
过滤数据并返回IQueryable<TSource>
或IEnumerable<TSource>
(参见 Reza Aghaei 的回答中的精彩解释)。
如果您想获得水产品,那么只需通过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...
这是因为Where
扩展方法返回IEnumerable<TSource>
.在 db set 的情况下,它返回IQueryable<TSource>
这是IEnumerable<TSource>
。
在您的情况下,由于您使用的是 async/await 模式,因此您可以使用 FirstOrDefaultAsync
来获取单个项目作为结果:
var p = await db.WatchedProducts.FirstOrDefaultAsync(u => u.ApplicationUserId == user.Id &&
u.ProductId == id)
你应该使用 SingleOrDefault
据我所知,您的结果应该是唯一的,因为您正在使用唯一的产品ID
var product = await Task.Run(()
=> db.SingleOrDefault(u => u.ApplicationUserId == user.Id && u.ProductId == id));
这将返回一个项目,如果未找到任何项目,则返回 null。注意,如果找到多个项目,它将引发异常,这不应该,因为产品 ID 很可能是唯一的,如果它找到更多,您会知道您在数据库中搞砸了您有多个具有相同 id 的产品
如果可以接受该查询可以包含多个记录作为结果,则使用 FirstOrDefault
而不是SingleOrDefault
,但逻辑就不太正确了,因为有一个需要返回一个或没有的查询来返回列表中的第一个是没有意义的。