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