简体   繁体   中英

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.

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.

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.

{
     "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'.

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?

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).

The simplest solution is multiply the rows after the query, 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();

We join ("inner") the newRental.MovieIds with the movies . 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

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..... :)

Edit: Do not use this! As xanatos correctly pointed out this is an antipattern. 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. 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

For Specific custmore

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

For newRental.customerId Only

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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