简体   繁体   中英

Complex linq to entity query

I have an EF model with 3 tables , Artist , Movie and Movie_Artist_Job . Movie_Artist_Job is just a foreign key table :

MovieId,ArtistId,JobId.

I m trying to get a results like this :

ArtistName1, Movie1

ArtistName1, Movie2

Artistname2, Movie1

Artistname2, Movie3

etc...

Right now I am doing this :

var query = (
    from items in _objEntities.Movie_Artist_Job
    where items.Artist.FulleName != string.Empty
    select items.Artist.FulleName).Distinct<string>();

List<ThumbItem> Items = new List<ThumbItem>();

foreach (string fullName in query)
{
    var matching = (
        from movie in _objEntities.Movie_Artist_Job
        where movie.Artist.FulleName == fullName
        select movie.Movie)
        .Distinct<Movie>();

    if (matching.Count() > 0)
    {
        foreach (Movie movies in matching)
        {
            if (movies != null && movies.IsDeleted == false)
            {
                new ThumbItem(fullName, movies.title);
            }
        }
    }
}

It works, but it takes ages...

Any clue on how to optimism this ?

Thanks a lot for your help.

You query the database inside a loop. This results in N + 1 queries. Try rewriting your code to the following:

var query = (
    from items in _objEntities.Movie_Artist_Job
    where items.Artist.FulleName != string.Empty
    select items.Artist.FulleName)
    .Distinct();

var matching =
    from fullName in query
    from movie in _objEntities.Movie_Artist_Job
    where movie.Artist.FulleName == fullName
    where !movies.IsDeleted
    select new { movie.fullName, movie.title })
    .Distinct()
    .ToArray();

List<ThumbItem> Items = (
    from movie in matching
    select new ThumbItem(movie.fullName, movie.title))
    .ToList();

You are handling many many relationship in a bit awkward manner. The easier approach will be to have this table as following with an primary key

public class Movie_Artist_Job
{
    public int Id { get; set; }
    public Artist Artist { get; set; }
    public Movie Movie { get; set; }
}

Then, simply call db.Movie_Artist_Job.ToList()

i've tried to replicate the DB you mentioned: -

  1. Artists
  2. Movies
  3. Jobs

and i add one entity class thumbItem as the following; to select items to: -

internal class ThumbItem
{
    public string ArtistName { set; get; }
    public string MovieName { set; get; }
}

and i have performed the following function to get the result you requested: -

MoviesEntities context = new MoviesEntities();

        var Thumbs = from artist in context.Artists
                     join job in context.Jobs on artist.ID equals job.ArtistID
                     join movie in context.Movies on job.MovieID equals movie.ID
                     select new ThumbItem()
                                {
                                    ArtistName = artist.Name,
                                    MovieName = movie.Name
                                };


        dataGridView1.DataSource = Thumbs;

it worked very fast and didn't take anything, i think your problem was that you separated the matching and the creation of controls into different steps other than performing a join statement with select into entity; which was the time consuming action.

EDIT: -

New Question from comment: - need the number of movies per artist from the same query?

just add this code after the one before it'll get you the result with DB round trip: -

var ListByArtist = Thumbs.ToList().GroupBy(l => l.ArtistName).Select(lg => new
                        {
                            Artist = lg.Key,
                            NumberOfMovies = lg.Count()
                        });

What you are trying to do is called "pivoting", you should take a look at Linq Extensions Library on how to achieve this on a properly build EF model.

As a side note, the all point of EF is to be able to write your queries in natural object oriented way, that is you shouldn't care much about "Movie_Artist_Job" table on the C# side of things (Calling Artist.Movies should return the list of movies for a given artist)

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