实体框架 - Linq NOT IN 查询

5

我看到了其他几篇类似的帖子,但老实说,我很困惑。 我正在尝试在EntityFarmework和Linq中执行以下sql语句,但无法使'NOT IN'和'UNION'正常工作。

SELECT LmsTeam.* FROM LmsTeam
INNER JOIN Game ON LmsTeam.GameId = Game.ID 
WHERE LmsTeam.Id NOT IN 
(SELECT TeamHomeId as TeamID FROM LmsEventMatch WHERE EventId =1
UNION
SELECT TeamAwayId as TeamID FROM LmsEventMatch WHERE EventId =1)
AND LmsTeam.GameId = 1 AND LmsTeam.Active = 1

我已经拥有下面的join和一些where子句,但无法完成NOT INUNION子句。

from t in LmsTeams
join g in Games on t.GameId equals g.Id
  where t.GameId == 1 && t.Active == true
  select t
4个回答

3

您觉得怎么样:

from t in LmsTeams
join g in Games on t.GameId equals g.Id
where t.GameId == 1 && t.Active == true && !(
        (from m in LmsEventMatch where m.EventId == 1 select m.TeamHomeId).Union(
         from m in LmsEventMatch where m.EventId == 1 select m.TeamAwayId)
    ).Contains(t.Id)
select t

我还没有测试它,因为没有你的数据上下文,但我认为应该这样做。

更新

我认为你可以避免在这里使用Union

from t in LmsTeams
join g in Games on t.GameId equals g.Id
where t.GameId == 1 && t.Active == true && !(
        LmsEventMatch.Where(m => m.EventId == 1).SelectMany(m => new int[] { m.TeamHomeId, TeamAwayId })
    ).Contains(t.Id)
select t

我在 LinqPad 中尝试了一下,但出现了错误:无法创建类型为“LastManStanding.DalEF.Entity.LmsEventMatch”的常量值。在此上下文中,仅支持基元类型或枚举类型。 - gisWeeper
奇怪的是,这个查询在 LinqPad 中不起作用,但在代码中完美地运行了 - 感谢您的答案,现在我只需要开始理解它! - gisWeeper
也许是我做错了什么,但这只有在排除集为空的情况下才能起作用,否则我会得到上述的“无法创建类型为...的常量值”的错误。N Rocking的外连接解决方案对我很有效。(EF 6.1) - Marc L.

1
另一种解决方案是使用左外连接并保留连接列为空的记录。
以下是一个示例:
var query = db.Categories    
  .GroupJoin(db.Products,
      Category => Category.CategoryId,
      Product => Product.CategoryId,
      (x, y) => new { Category = x, Products = y })
  .SelectMany(
      xy => xy.Products.DefaultIfEmpty(),
      (x, y) => new { Category = x.Category, Product = y })
  .Where(w => w.Product.CategoryId == null)
  .Select(s => new { Category = s.Category});

0

您可以按照以下方式编写和分割查询,这将轻松解决您的问题。

还请查看我的帖子:SQL to LINQ(第7种情况-使用IN和NOT IN子句过滤数据)

//first do the union of two
var query = ((from d in  LmsEventMatch 
             where d.EventId == 1
              select d.TeamHomeId).
        Union(from e in  LmsEventMatch 
                       where e.EventId == 1
                          select e.TeamAwayId));

//than perform !contains operation for no in
var records =( from t in LmsTeams
join g in Games on t.GameId equals g.Id
  where t.GameId == 1 && t.Active == true && !query.Contains(t.Id)
  select t).ToList();

在LINQ查询中,in和not in的图形表示

enter image description here


如果要将 SQL 转换为 LINQ,您可以使用:Linqer 输入图像描述


“where d.EventId equals 1” - 你确定这个语法正确吗?它不是一个“join”条件。在你的“list”声明中使用“ToList()”是另一个问题 - 它会导致至少2个数据库请求。 - MarcinJuraszek
还是不正确。from d in TeamID。这里的TeamID是什么?!? - MarcinJuraszek
我会尝试一下并回复您 - 这是否可以在单个查询中完成,还是我需要使用两个查询? - gisWeeper
@bsheehy01 - 您可以像上面的答案中所做的那样在单个查询中完成它...但我是这样写的,以便易于理解...最终,这两个查询会转换为一个您可以在SQL分析器中看到的查询。 - Pranay Rana
我试了你的代码,它起作用了 - 谢谢你的建议。如果我能把你和MarcinJuraszek标记为答案,我会的,但是MarcinJuraszek先到了。 - gisWeeper
@bsheehy01 - 谢谢,我更新了我的答案,你可以使用 Linqer 将 SQL 查询转换为 Linq。 - Pranay Rana

0
var homeIds = LmsEventMatch.Where(em => em.Eventid == 1)
                           .Select(em => em.TeamHomeId);
var awayIds = LmsEventMatch.Where(em => em.Eventid == 1)
                           .Select(em => em.TeamAwayId);
var allIds = homeIds.Union(awayIds);

var query = LmsTeams.Where( 
                t => !allIds.Contains( t.Id ) && t.Active == 1 && t.GameId == 1);

@PranayRana 好的,原帖中没有从Game中选择任何内容。 - Phil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接