简体   繁体   English

如何使用linq检索一个以上唯一ID的实例?

[英]How to retrieve more than one instance of a unique Id with linq?

I have a post action in my API which creates an order based off some data it retrieves from a view model. 我的API中有一个后期操作,该操作根据从视图模型检索到的一些数据来创建订单。

It needs to be able to retrieve all movies from a table of 'movies' that are passed to it via the view model and create an order. 它需要能够从通过视图模型传递给它的“电影”表中检索所有电影,并创建订单。 The view model passes the action the Ids of the movies it needs to retrieve. 视图模型传递需要检索的电影ID的操作。

I have a working solution, and when giving the action data like this it works: 我有一个有效的解决方案,当提供这样的动作数据时,它可以工作:

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

database: 数据库:

在此处输入图片说明

However when I give the action data which contains two or more movies with the same Id, it only ever saves one movie. 但是,当我提供包含两个或多个具有相同ID的电影的动作数据时,它只能保存一部电影。

{
     "movieIds": [34, 34],
     "customerId": 21
}

database: 数据库:

在此处输入图片说明

After debugging the code, i found out that it's this linq statement which is causing the problem, it only ever saves one instance of the movie to 'movies'. 调试代码后,我发现正是这个linq语句导致了问题,它只将电影的一个实例保存到“电影”中。

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

Does anyone know why it does this? 有谁知道为什么这样做? and how to construct a linq statement that allows it to save multiple Ids? 以及如何构造一个linq语句来保存多个ID?

If you think in SQL terms, what you ask is quite complex (not too much, but probably impossible for the Entity Framework LINQ translator-to-SQL). 如果您以SQL的方式来考虑,那么您所要问的是相当复杂的(不是太多,但对于Entity Framework LINQ转换为SQL来说可能是不可能的)。

The simplest solution is multiply the rows after the query, C#-side. 最简单的解决方案是将查询后的行乘以C#端。

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();

We join ("inner") the newRental.MovieIds with the movies . 我们join (“内部”)的newRental.MovieIdsmovies In this way the rows are "multiplied" when necessary. 这样,在必要时行被“相乘”。

You need to select movies from your list passed in, NOT from the list of movies in the database. 您需要从传入的列表中选择电影,而不是从数据库中的电影列表中选择。 In SQL terms, what you're saying is 用SQL术语来说,你的意思是

select * from movies where movieId in (34,34)

Which will of course return only one row. 当然,那只返回一行。 What you need instead is to select one movie for each entry in your list. 相反,您需要为列表中的每个条目选择一部电影。 This will be less efficient for longs lists of movies, but I assume that's unlikely to be a huge problem. 对于一长串的电影,这将不太有效,但是我认为这不太可能成为一个大问题。

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();

That should do what you want. 那应该做你想要的。

For a more convoluted, but probably more DB-efficient solution, you could instead do this: 对于更复杂但可能更有效的数据库解决方案,您可以执行以下操作:

//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();

And that would fetch all movies in one statement then use that list to match up the requested list. 这样一来就可以提取所有电影,然后使用该列表来匹配所请求的列表。 You could almost certainly do this in a more terse way, but this is clear and obvious - when you look at this in 2 month's time it won't confuse you..... :) 您几乎可以肯定会以更简洁的方式执行此操作,但这是显而易见的-当您在2个月的时间内查看此内容时,不会使您感到困惑。

Edit: Do not use this! 编辑:不要使用这个! As xanatos correctly pointed out this is an antipattern. 正如xanatos正确指出的那样,这是一种反模式。 I'll let it stand as it is for learning purposes! 我会让它原样用于学习目的!

This line of code returns just one element since in _context.Movies is per se only one movie with the id 34 stored. 这行代码仅返回一个元素,因为在_context中。Movies本身仅是一部ID为34的电影。 I'd change the line to: 我将其更改为:

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

This way you gain a result for each new rental no matter if it's stored only once. 这样,无论新租金仅存储一次,您都会获得结果。

You can try below,May this will help you 您可以在下面尝试,希望这对您有帮助

i guess newRental.MovieIds is array which contain List of MovieIds 我猜newRental.MovieIds是包含MovieIds列表的MovieIds

For Specific custmore 对于特定的客户

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

For newRental.customerId Only 仅适用于newRental.customerId

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM