【问题标题】:Get results matching a list of Ids using Linq使用 Linq 获取与 Id 列表匹配的结果
【发布时间】:2017-06-15 11:19:12
【问题描述】:

我正在尝试获取满足List<int> 中包含的所有genreIds 的gameIds 列表。

表格(部分):

编辑列表:

  • game_id
  • 内容

game_genres(游戏可以属于多种类型):

  • 身份证
  • game_id
  • genre_id

我需要获取 game_genres 表中所有 genre_id 的游戏 ID 列表。

例如:

genre_id 的列表包括类型 2 和 3。

如果game_genres 表中存在genre_id = 2 和genre_id = 3 的Game Id = 14。那么它将包含在最终结果中。

这是我的代码:

 // get the list of game_id's that have an editorial
 var editorialList = (from ee in db.editorials where ee.is_enabled == true select new {
     game_id = ee.game_id
 }).ToList();

// Produce a list of the games in the editorials and their genre Ids that the belong to
 var gameAndGenres = (from el in editorialList join gg in db.game_genres
  on el.game_id equals gg.game_id

     select new {
         game_id = el.game_id,
             genre_id = gg.genre_id
     }
 );

 var res = gameAndGenres.Where(
  x => x.genres.Contains(x.genre_id)) == genres.Count; // stuck here

最终结果应该是一个唯一的 game_id 列表,列表中的每个游戏属于在流派List<int> 中列出的所有流派。

我创建了几个步骤来帮助我理解查询,但它可能能够在一行中解决,我只是无法解决它。

更新:这是我正在尝试的新代码。

 var res = gameAndGenres.GroupBy(x => x.game_id)
  .Select(g => new {
   game_id = g.Key,
   genreIds = g.Select( c => c.genre_id)

   });

   var res2 = res.Where(x => genres.Intersect(x.genreIds).Count()
  == genres.Count()).ToList();

【问题讨论】:

    标签: c# sql asp.net entity-framework linq


    【解决方案1】:

    游戏和流派之间的关系是多对多的:Game 可以属于零个或多个流派,Genre 可以包含零个或多个游戏。

    您想要game-genres 表中属于所有类型的所有游戏(的 ID)。

    例如,如果您的游戏流派列表仅包含引用流派 2 和流派 3 的记录,那么您需要属于流派 2 和 3 的所有游戏。

    请注意,可能存在不属于任何“游戏”的Genre。在这种情况下,game-genres 表中没有引用此Genre 的记录。

    下面是您的属性实体框架类的示例。类和属性的实际名称可能会有所不同,但您会得到 Id

    public class Game
    {
        public int GameId {get; set;}
        public virtual ICollection<Genre> Genres {get; set;}
        ... // other properties
    }
    public class Genre
    {
        public int GenreId {get; set;
        public virtual ICollection<Game> Games {get; set;}
        ...
    }
    public MyDbContext : DbContext
    {
        public DbSet<Game> Games {get; set;}
        public DbSet<Genre> Genres {get; set;}
        ...
    }
    

    实体框架模型构建器将检测到 Games 和 Genres 之间存在多对多关系,并会自动添加一个类似于“game-genres”的表。

    好消息是,如果某个流派不属于任何游戏,它就不会出现在您的 game_genres 表中。反之亦然:如果您的游戏类型表中有一个元素,那么至少有一款游戏属于该类型。

    因此,您不需要所有类型,您只需要至少有一个Game 使用的类型。

    IEnumerable<Genre> usedGenres = dbContext.Genres
        .Where(genre => genre.Games.Any());
    

    现在您只需要属于usedGenres 中每个类型的Games = usedGenres 的每个元素都在集合 Game.Genres 中的每个游戏。

    要检查一个流派是否在 Game.Genres 的集合中,我们只需将 Game.Genres 的 GenreId 与 usedGenreIds 的 GenreId 进行比较

    IEnumerable<int> usedGenreIds = usedGenres
        .Select(genre => genre.GenreId);
    IEnumerable<Game> gamesWithAllUsedGenres = dbContext.Games
        .Where(game => usedGenreIds.All(genreId => game.Genres.Select(genre => genre.GenreIdContains(genreId));
    

    【讨论】:

      【解决方案2】:

      类似这样的:

              var gamesIds = db.editorials
                  .Where(e => db.game_genres.Select(gg => gg.genre_id).Distinct().All(genId => db.game_genres.Any(gg => gg.game_id == e.game_id && gg.genre_id == genId)))
                  .Select(e => e.game_id)
                  .ToList();
      

      从社论中选择 game_id,其中 game_id 包含 game_genre 表中所有不同的genre_id 的条目。

      如果您希望所有游戏都在列表中而不是在表格中包含所有类型:

      List<int> genreIds = new List<int>() {1,2,3};
      
          var gamesIds = db.editorials
              .Where(e => genreIds.All(genId => db.game_genres.Any(gg => gg.game_id == e.game_id && gg.genre_id == genId)))
              .Select(e => e.game_id)
              .ToList();
      

      【讨论】:

      • 在哪里使用 List,其中包含游戏应遵守的类型列表
      • 啊,我不明白在你的问题中,你想要一个列表中包含所有类型的所有游戏——而不是表中的所有游戏?
      【解决方案3】:

      您可以通过对表格中的行进行分组来实现。

      使用 Lambda 表达式:

      var res = db.game_genres.GroupBy(gg => gg.game_id)
          .Where(g => g.Count() == db.genres.Count())
          .Select(x => x.Key).ToList();
      

      或使用 LINQ:

       var res = (from gg in db.game_genres
                   group gg by gg.game_id into g
                   where g.Count() == db.genres.Count()
                   select g.Key).ToList();
      

      这样的分组会为每个game_id 生成一条记录(称为组)。每个组的Key 是“group by”子句中使用的game_id。每个组都是具有相等game_id 的行的集合,因此您可以像对待任何其他数据库实体集合一样对待它,在这里您使用where 语句对其进行过滤并在集合上调用Count()

      【讨论】:

      • 这将非常无效,因为game_genres有所有游戏的类型,我只想要那些有编辑内容的人。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2021-06-20
      相关资源
      最近更新 更多