哪个LINQ查询从1个表中选择不在另一个表中的行

时间:2012-07-11 15:35:59

标签: c# linq entity-framework linq-to-entities

我正在开发一个应用程序,其中有2个不同的实体,Products和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, joining 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;
}

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

谢谢,

3 个答案:

答案 0 :(得分:5)

从原始查询中获取不同的记录可以获得所需的结果。注意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

此时您将获得重复的产品。我添加的不同功能将获取此列表并删除除一个重复条目之外的所有条目。离开你,

where !p.Sold

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

此外,您的第二个查询缺少第一个查询中的{{1}}。

答案 1 :(得分:3)

我感觉你无意中咆哮了错误的树。

这是一个简单的场景:

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

基本上,您需要一个交易,关键部分,单身或类似设备,以确保只有一个人可以检查添加到购物车中单一操作 - 它必须成功或失败作为一个单一的工作单元。

答案 2 :(得分:1)

请查看此问题:LINQ to Entity, joining on NOT IN tables。比上述解决方案更清洁。

查看您的查询,没有任何内容可以防止重复记录显示。您需要使用此:How do I use Linq to obtain a unique list of properties from a list of objects?

相关问题