5

我正在开发一个应用程序,其中有 2 个不同的实体、产品和 ShoppingCarts。每个产品都是唯一的,并且具有唯一的标识符。我想添加尚未在另一个购物车中且未出售到 ShoppingCart 的产品。

产品实体简化:

public class Products
{
    public int Id { get; set; }
    public string Name{ get; set; }
    public bool Sold { get; set; }
}

购物车实体简化:

public class ShoppingCarts
{
    public int Guid Guid { get; set; }
    public int ProductId { get; set; }
}

因此,首先我检索所有 Product.Id,然后将它们添加到我的购物车中。我的方法如下所示:

private IQueryable<Products> GetAvailableProductId(int quantity)
{
    var query = (from p in _context.Set<Products>()
                join sc in _context.Set<ShoppingCarts>() on p.Id equals sc.ProductId into subset
                from sc in subset.DefaultIfEmpty()
                where !p.Sold && sc == null
                select p).Take(quantity);
    return query;
}

出于某种原因,每隔一段时间,就会将具有相同 ProductId 的 2 个实体添加到不同的购物车中。这使该应用程序能够销售 2 个相同的产品。我最终通过在进行交易之前在应用程序中执行另一次检查来解决此问题。

我最近重新访问了代码并遇到了这些帖子 LINQ Query: Determining if object in one list exists in another based on key LINQ to Entity, join on NOT IN tables

我的问题是,如果将我的查询更改为这样的内容会阻止双重添加。

private IQueryable<Products> NewGetAvailableProductId(int quantity)
{
    var query = (from p in _context.Set<Products>()
                where !_context.Set<ShoppingCarts>().Any(x => x.ProductId == p.Id) &&  !p.Sold
                select p).Take(quantity);
    return query;
}

如果有任何疑问,请告诉我,以便我更好地解释这一点。

谢谢,

4

3 回答 3

6

从原始查询中获取不同的记录应该会为您提供所需的结果。注意 Take() 之前的 Distinct()。

var query = (from p in _context.Set<Products>()
                join sc in _context.Set<ShoppingCarts>() on p.Id equals sc.ProductId into subset
                from sc in subset.DefaultIfEmpty()
                where !p.Sold && sc == null
                select p).Distinct().Take(quantity);

您得到重复的原因是原始查询将为您提供产品表和购物车表之间的匹配列表。例如,如果您有product1并且cart1没有购物车cart2product2您将从加入中获得以下结果。

product1, cart1
product1, cart2
product2, null

然后你过滤掉空购物车

product1, cart1
product1, cart2

然后您只选择产品对象

product1
product1

此时,您只剩下重复的产品。然后,我添加的不同功能将获取此列表并删除除一个重复条目之外的所有条目。留给你,

product1

值得检查每个查询生成的 sql,因为即使它们产生相似的结果,它们也可能完全不同。我怀疑您的第一个查询将使用 LEFT OUTER JOIN 而第二个查询将使用 IN 子句。我会使用 LEFT OUTER JOIN,因为根据我的经验,IN 子句相当慢,应尽可能避免使用。显然,您应该在自己的环境中进行测量。

此外,您的第二个查询缺少where !p.Sold第一个查询。

于 2012-07-11T15:57:13.987 回答
3

我有一种感觉,你无意中在错误的树上吠叫。

这是简而言之的场景:

  • 用户 1 想要购买该产品。该应用程序检查它是否在任何购物车中。不。
  • 用户 2 想要购买该产品。该应用程序检查它是否在任何购物车中。不。
  • 用户 1 的线程完成了将其添加到购物车的过程。
  • 用户 2 的线程完成了将其添加到购物车的过程。它假定,由于先前的检查成功,因此这样做仍然是安全的。

基本上,您需要一个事务、临界区、单例或一些类似的设备,以确保只有一个人可以将其作为单个操作检查添加到他们的购物车中——它必须作为单个工作单元成功或失败。

于 2012-07-11T16:29:55.740 回答
1

请查看这个问题:LINQ to Entity, join on NOT IN tables。比上述解决方案更清洁的方法。

查看您的查询,没有什么可以防止重复记录出现。您需要使用这个:如何使用 Linq 从对象列表中获取唯一的属性列表?

于 2013-01-14T16:13:18.250 回答