C# 如何使用linq检索唯一Id的多个实例?

C# 如何使用linq检索唯一Id的多个实例?,c#,entity-framework,linq,asp.net-web-api,C#,Entity Framework,Linq,Asp.net Web Api,我的API中有一个post操作,它根据从视图模型检索到的一些数据创建订单 它需要能够从通过视图模型传递给它的“电影”表中检索所有电影,并创建订单。视图模型将动作传递给它需要检索的电影的ID 我有一个有效的解决方案,当提供这样的行动数据时,它是有效的: { "movieIds": [34, 35], "customerId": 21 } 数据库: 但是,当我给出包含两个或多个具有相同Id的电影的动作数据时,它只保存一个电影 { "movieIds": [34, 34

我的API中有一个post操作,它根据从视图模型检索到的一些数据创建订单

它需要能够从通过视图模型传递给它的“电影”表中检索所有电影,并创建订单。视图模型将动作传递给它需要检索的电影的ID

我有一个有效的解决方案,当提供这样的行动数据时,它是有效的:

{
     "movieIds": [34, 35],
     "customerId": 21
}
数据库:

但是,当我给出包含两个或多个具有相同Id的电影的动作数据时,它只保存一个电影

{
     "movieIds": [34, 34],
     "customerId": 21
}
数据库:

调试代码后,我发现是这个linq语句导致了问题,它只将电影的一个实例保存到“movies”中

movies = _context.Movies.Where(m => newRental.MovieIds.Contains(m.Id)).ToList();

有人知道为什么会这样吗?以及如何构造一个允许它保存多个ID的linq语句?

如果您用SQL的术语思考,您所要求的是相当复杂的,不是太多,但对于实体框架linq translator to SQL来说可能是不可能的

最简单的解决方案是将查询后的行相乘,C-side

var movies = _context.Movies.Where(m => newRental.MovieIds.Contains(m.Id)).ToList();

var movies2 = (from x in newRental.MovieIds
               join y in movies on x equals y.Id
               select y).ToList();

我们将newrent.MovieIds与电影结合在一起。通过这种方式,行会在必要时相乘。

如果您用SQL的术语思考,您所要求的内容相当复杂,不太多,但对于实体框架LINQ translator to SQL来说可能是不可能的

最简单的解决方案是将查询后的行相乘,C-side

var movies = _context.Movies.Where(m => newRental.MovieIds.Contains(m.Id)).ToList();

var movies2 = (from x in newRental.MovieIds
               join y in movies on x equals y.Id
               select y).ToList();
我们将newrent.MovieIds与电影结合在一起。这样,行在必要时就会相乘。

编辑:不要使用此选项!正如xanatos正确指出的,这是一种反模式。为了学习,我会让它保持原样

这行代码只返回一个元素,因为in_context.Movies本身只存储了一个id为34的电影。我想把线路改成:

movies = newRental.MovieIds.Select(movieId => _context.Movies.SingleOrDefault(m => m.Id == movieId)).ToList();
这样,无论每次新租赁是否只存储一次,您都会获得一个结果。

编辑:不要使用此选项!正如xanatos正确指出的,这是一种反模式。为了学习,我会让它保持原样

这行代码只返回一个元素,因为in_context.Movies本身只存储了一个id为34的电影。我想把线路改成:

movies = newRental.MovieIds.Select(movieId => _context.Movies.SingleOrDefault(m => m.Id == movieId)).ToList();

这样,无论每次新租赁是否只存储一次,您都会获得一个结果。

您可以在下面尝试,这可能会对您有所帮助

我猜newrent.MovieIds是包含电影ID列表的数组

有关具体信息,请参阅更多

movies = _context.Movies
                 .Where(m => newRental.MovieIds.Contains(m.Movie_Id) && m.customerId==21)
                 .ToList();
仅适用于newRental.customerId

movies = _context.Movies
                 .Where(m => newRental.MovieIds.Contains(m.Movie_Id) && newRental.customerId.contains(m.Customer_Id ))
                 .ToList();

你可以试试下面,也许这会对你有帮助

我猜newrent.MovieIds是包含电影ID列表的数组

有关具体信息,请参阅更多

movies = _context.Movies
                 .Where(m => newRental.MovieIds.Contains(m.Movie_Id) && m.customerId==21)
                 .ToList();
仅适用于newRental.customerId

movies = _context.Movies
                 .Where(m => newRental.MovieIds.Contains(m.Movie_Id) && newRental.customerId.contains(m.Customer_Id ))
                 .ToList();

您需要从传入的列表中选择电影,而不是从数据库中的电影列表中选择。 用SQL术语来说,您所说的是

select * from movies where movieId in (34,34)
这当然只会返回一行。 相反,您需要为列表中的每个条目选择一部电影。这对于一长串的电影来说效率较低,但我认为这不太可能是一个大问题

movies = newRental.MovieIds
.Select(rm => _context.Movies.FirstOrDefault(m => m.Id==rm)
.Where(x => x != null) //Just make sure no entries are NULL.. optional
.ToList();
那应该是你想要的

对于更复杂但可能更高效的解决方案,您可以这样做:

//Get list of matches from DB into a list in one hit.
var possibleMovies = _context.Movies.Where(m=>newRental.MovieIds.Contains(m.Id)).ToList();

//Match up entries in request to DB entries.
movies = newRental.MovieIds
    .Select(rm => possibleMovies.FirstOrDefault(m => m.Id==rm))
    .Where(x => x != null) //Just make sure no entries are NULL.. optional
    .ToList();

这将在一条语句中获取所有电影,然后使用该列表匹配请求的列表。你几乎可以肯定地用一种更简洁的方式来做这件事,但这是清楚和明显的——当你在2个月后看这件事时,它不会让你感到困惑

您需要从传入的列表中选择电影,而不是从数据库中的电影列表中选择电影。 用SQL术语来说,您所说的是

select * from movies where movieId in (34,34)
这当然只会返回一行。 相反,您需要为列表中的每个条目选择一部电影。这对于一长串的电影来说效率较低,但我认为这不太可能是一个大问题

movies = newRental.MovieIds
.Select(rm => _context.Movies.FirstOrDefault(m => m.Id==rm)
.Where(x => x != null) //Just make sure no entries are NULL.. optional
.ToList();
那应该是你想要的

对于更复杂但可能更高效的解决方案,您可以这样做:

//Get list of matches from DB into a list in one hit.
var possibleMovies = _context.Movies.Where(m=>newRental.MovieIds.Contains(m.Id)).ToList();

//Match up entries in request to DB entries.
movies = newRental.MovieIds
    .Select(rm => possibleMovies.FirstOrDefault(m => m.Id==rm))
    .Where(x => x != null) //Just make sure no entries are NULL.. optional
    .ToList();
这将在一条语句中获取所有电影,然后使用该列表匹配请求的列表。你几乎可以肯定地用一种更简洁的方式来做这件事,但这是清楚和明显的——当你在2个月后看这件事时,它不会让你感到困惑

我在您的LINQ查询中没有看到MovieID和customerId…我在您的LINQ查询中没有看到MovieID和customerId…这实际上被称为SELECT N+1反模式。在这个特殊情况下,它是SELECT N反模式。。。您正在执行N个不同的查询,而查询的开销是获取N行。当N稍微增长时,总时间以相同的速度增长。。。如果N约为1000,则会杀死SQL Server。请看,这被称为SELECT N+1反模式,实际上在这个特殊情况下,它是SELECT N反模式。。。您正在执行N个不同的查询,而查询的开销是获取N行。当N稍微增长时,总时间以相同的速度增长。。。如果N约为1000,则会杀死SQL Server。看看我的情况
此方法效果最好,谢谢分享。对于我的情况,此方法效果最好,谢谢分享。