2016-03-26 7 views
0

I Film Meta-Daten aus und API bin das Abrufen und das Hinzufügen von ihnen Datenbank Entity Framework mit dem folgenden CodeWie dieser Entity Framework Code optimieren

public static Movy AddOrUpdate(this TMDbLib.Objects.Movies.Movie Movie, TMDB Context = null) 
{ 
    //Check for duplicate items on every add() within foreach or for 

    if (Movie == null) 
     return null; 
    if (string.IsNullOrEmpty(Movie.Title)) 
     return null; 

    //Managing IMDBID 
    var ImdbID = Movie.ImdbId; 
    if (!string.IsNullOrWhiteSpace(ImdbID)) 
     ImdbID = ImdbID.Replace("/", "").Replace("tt", ""); 
    var IMDBID = 0; 
    var TryParse = int.TryParse(ImdbID, out IMDBID); 
    if (TryParse == false || IMDBID == 0) 
     return null; 
    if (Context == null) 
     Context = Settings.EntityContexts.EntityContexts.TMDBContext; 
    Context.Configuration.LazyLoadingEnabled = true; 
    var Movy = Context.Movies.Where(My => My.ID == Movie.Id).FirstOrDefault(); 
    if (Movy == null) 
    { 
     Movy = new Movy(); 
     Movy.UrlTag = AspExtension.AspTools.StringHelper.Slugify(Movie.Title, MaxLength: 50); 
     Movy = Context.Movies.Add(Movy); 
    } 
    else 
    { 
    } 

    Movy.ImdbID = IMDBID; 

    Movy.ID = Movie.Id; 
    AspExtension.AspTools.StringHelper.MapObjects(Movie, Movy); 
    Movy.Adult = Movie.Adult ? 1 : 0; 

    if (Movie.AlternativeTitles != null && Movie.AlternativeTitles.Titles != null && Movie.AlternativeTitles.Titles.Count > 0) 
    { 
     if (Movy.AlternativeTitles == null) 
     { 
      Movy.AlternativeTitles = new List<Entities.TMDB.AlternativeTitle>(); 
     } 
     foreach (var AlternativeTitle in Movie.AlternativeTitles.Titles) 
     { 
      var DBAlternativeTitle = Movy.AlternativeTitles.Where(My => My.Title == AlternativeTitle.Title && My.Iso_3166_1 == AlternativeTitle.Iso_3166_1).FirstOrDefault(); 

      if (DBAlternativeTitle == null) 
      { 
       DBAlternativeTitle = new Entities.TMDB.AlternativeTitle(); 
       Movy.AlternativeTitles.Add(DBAlternativeTitle); 
      } 

      DBAlternativeTitle.Title = AlternativeTitle.Title; 
      DBAlternativeTitle.Movy = Movy; 
      DBAlternativeTitle.MovieID = Movy.ID; 
      DBAlternativeTitle.Iso_3166_1 = AlternativeTitle.Iso_3166_1; 
     } 
    } 

    Movy.Budget = Movie.Budget; 

    if (Movie.Genres != null && Movie.Genres.Count > 0) 
    { 

     //This is a many to many relation ship, so first check if the genre is exsiting. if yes then use it. 
     // else just create new and populate it and add it to movie and add movie to genre and entity 
     //will create the records for u. 


     //Retrieve genres 
     var APIGenreIds = Movie.Genres.Select(My => My.Id).ToList(); 
     var DBGenres = Context.Genres.Where(My => APIGenreIds.Contains(My.ID)).ToList(); 

     if (Movy.Genres == null) Movy.Genres = new List<Entities.TMDB.Genre>(); 
     foreach (var APIGenre in Movie.Genres) 
     { 
      var DBGenre = DBGenres.Where(My => My.ID == APIGenre.Id).FirstOrDefault(); 
      if (DBGenre == null) 
      { 
       DBGenre = new Entities.TMDB.Genre(); 
      } 
      DBGenre.ID = APIGenre.Id; 
      DBGenre.Name = APIGenre.Name; 
      DBGenre.Movies.Add(Movy); 
      Movy.Genres.Add(DBGenre); 
     } 
    } 

    //One to many relationship. Check and add. 
    if (Movie.Images != null && Movie.Images.Posters.Count > 0) 
    { 
     if (Movy.Images == null) Movy.Images = new List<Entities.TMDB.Image>(); 
     foreach (var APIImage in Movie.Images.Posters) 
     { 
      var DBImage = Movy.Images.Where(My => My.FilePath == APIImage.FilePath).FirstOrDefault(); 
      if (DBImage == null) 
      { 
       DBImage = new Entities.TMDB.Image(); 
       Movy.Images.Add(DBImage); 
      } 
      DBImage.AspectRatio = (decimal)APIImage.AspectRatio; 
      DBImage.FilePath = APIImage.FilePath; 
      DBImage.Height = APIImage.Height; 
      DBImage.Iso_639_1 = APIImage.Iso_639_1; 
      DBImage.MovieID = Movy.ID; 
      DBImage.Movy = Movy; 
      DBImage.Type = "Poster"; 
      DBImage.VoteAverage = (decimal)APIImage.VoteAverage; 
      DBImage.VoteCount = APIImage.VoteCount; 
      DBImage.Width = APIImage.Width; 
     } 
    } 

    if (Movie.Images != null && Movie.Images.Posters.Count > 0) 
    { 
     if (Movy.Images == null) Movy.Images = new List<Entities.TMDB.Image>(); 
     foreach (var APIImage in Movie.Images.Posters) 
     { 
      var DBImage = Movy.Images.Where(My => My.FilePath == APIImage.FilePath).FirstOrDefault(); 
      if (DBImage == null) 
      { 
       DBImage = new Entities.TMDB.Image(); 
       Movy.Images.Add(DBImage); 
      } 
      DBImage.AspectRatio = (decimal)APIImage.AspectRatio; 
      DBImage.FilePath = APIImage.FilePath; 
      DBImage.Height = APIImage.Height; 
      DBImage.Iso_639_1 = APIImage.Iso_639_1; 
      DBImage.MovieID = Movy.ID; 
      DBImage.Movy = Movy; 
      DBImage.Type = "Poster"; 
      DBImage.VoteAverage = (decimal)APIImage.VoteAverage; 
      DBImage.VoteCount = APIImage.VoteCount; 
      DBImage.Width = APIImage.Width; 
     } 
    } 

    Movy.HomePage = Movie.Homepage; 

    if (Movie.Keywords != null && Movie.Keywords.Keywords != null & Movie.Keywords.Keywords.Count > 0) 
    { 
     //Retrieve Keywords 
     var APIKeywordIds = Movie.Keywords.Keywords.Select(My => My.Id).ToList(); 
     var DBKeywords = Context.Keywords.Where(My => APIKeywordIds.Contains(My.ID)).ToList(); 

     if (Movy.Keywords == null) Movy.Keywords = new List<Entities.TMDB.Keyword>(); 
     foreach (var APIKeyword in Movie.Keywords.Keywords) 
     { 
      var DBKeyword = DBKeywords.Where(My => My.ID == APIKeyword.Id).FirstOrDefault(); 
      if (DBKeyword == null) 
      { 
       DBKeyword = new Entities.TMDB.Keyword(); 
      } 
      DBKeyword.ID = APIKeyword.Id; 
      DBKeyword.Name = APIKeyword.Name; 
      DBKeyword.Movies.Add(Movy); 
      Movy.Keywords.Add(DBKeyword); 
     } 
    } 

    //Many to many, but this time joining table is consisting of a few other columns than 
    //just P Key and F Key 
    //So first check if person exist. if not add. 
    //Then check if cast object exists, if not add new 
    if (Movie.Credits != null && Movie.Credits.Cast != null && Movie.Credits.Cast.Count > 0) 
    { 
     //Retrieve Casts 
     var APICastIds = Movie.Credits.Cast.Select(My => My.Id).ToList(); //Person ids 
     var DBPersons = Context.Persons.Where(My => APICastIds.Contains(My.ID)).ToList(); 
     var DBMovie_Casts = Context.Movie_Casts.Where(My => My.MovieID == Movy.ID).ToList(); 

     if (Movy.Movie_Casts == null) Movy.Movie_Casts = new List<Entities.TMDB.Movie_Casts>(); 
     foreach (var APICast in Movie.Credits.Cast) 
     { 
      var DBPerson = DBPersons.Where(My => My.ID == APICast.Id).FirstOrDefault(); 
      if (DBPerson == null) 
      { 
       var LocalDBPerson = Context.Persons.Local.Where(My => My.ID == APICast.Id).FirstOrDefault(); 
       if (LocalDBPerson == null) 
       { 
        DBPerson = new Entities.TMDB.Person(); 
        DBPerson.ID = APICast.Id; 
        DBPerson = Context.Persons.Add(DBPerson); 
       } 
       else 
       { 
        DBPerson = LocalDBPerson; 
       } 
      } 


      DBPerson.Name = APICast.Name; 
      DBPerson.ProfilePath = APICast.ProfilePath; 

      var DBMovie_Cast = DBMovie_Casts.Where(My => My.MovieID == Movy.ID && My.CreditID == APICast.CreditId).FirstOrDefault(); 
      if (DBMovie_Cast == null) 
      { 
       DBMovie_Cast = new Movie_Casts(); 
       DBMovie_Cast.CastID = APICast.CastId; 
       DBMovie_Cast.CreditID = APICast.CreditId; 
      } 

      DBMovie_Cast.Cast_Order = APICast.Order; 
      DBMovie_Cast.Character = APICast.Character; 
      DBMovie_Cast.MovieID = Movy.ID; 
      DBMovie_Cast.Person = DBPerson; 
      DBMovie_Cast.PersonID = DBPerson.ID; 

      DBPerson.Movie_Casts.Add(DBMovie_Cast); 
      Movy.Movie_Casts.Add(DBMovie_Cast); 
      Context.SaveChanges(); 
     } 
    } 

    if (Movie.Credits != null && Movie.Credits.Crew != null && Movie.Credits.Crew.Count > 0) 
    { 
     //Retrieve Crews 
     var APICrewIds = Movie.Credits.Crew.Select(My => My.Id).ToList(); 
     var DBPersons = Context.Persons.Where(My => APICrewIds.Contains(My.ID)).ToList(); 
     var DBMovie_Crews = Context.Movie_Crew.Where(My => My.MovieID == Movy.ID).ToList(); 

     if (Movy.Movie_Crew == null) Movy.Movie_Crew = new List<Movie_Crew>(); 
     foreach (var APICrew in Movie.Credits.Crew) 
     { 
      var DBPerson = DBPersons.Where(My => My.ID == APICrew.Id).FirstOrDefault(); 

      if (DBPerson == null) 
      { 
       if (Context.Persons.Local.Where(My => My.ID == APICrew.Id).FirstOrDefault() == null) 
       { 
        DBPerson = new Entities.TMDB.Person(); 
        DBPerson.ID = APICrew.Id; 
        Context.Persons.Add(DBPerson); 
       } 
       else 
       { 
        DBPerson = Context.Persons.Local.Where(My => My.ID == APICrew.Id).FirstOrDefault(); 
       } 

      } 


      DBPerson.Name = APICrew.Name; 
      DBPerson.ProfilePath = APICrew.ProfilePath; 

      var DBMovie_Crew = DBMovie_Crews.Where(My => My.MovieID == Movy.ID && My.CreditID == APICrew.CreditId).FirstOrDefault(); 
      if (DBMovie_Crew == null) 
      { 
       DBMovie_Crew = new Movie_Crew(); 
      } 

      DBMovie_Crew.Department = APICrew.Department; 
      DBMovie_Crew.Job = APICrew.Job; 
      DBMovie_Crew.CreditID = APICrew.CreditId; 
      DBMovie_Crew.MovieID = Movy.ID; 
      DBMovie_Crew.Person = DBPerson; 
      DBMovie_Crew.PersonID = DBPerson.ID; 

      DBPerson.Movie_Crew.Add(DBMovie_Crew); 
      Movy.Movie_Crew.Add(DBMovie_Crew); 
     } 
    } 


    //Many to many, just like genres 
    if (Movie.ProductionCompanies != null && Movie.ProductionCompanies.Count > 0) 
    { 
     //Retrieve ProductionCompanies 
     var APIProductionCompanyIds = Movie.ProductionCompanies.Select(My => My.Id).ToList(); 
     var DBProductionCompanies = Context.ProductionCompanies.Where(My => APIProductionCompanyIds.Contains(My.ID)).ToList(); 

     if (Movy.ProductionCompanies == null) Movy.ProductionCompanies = new List<Entities.TMDB.ProductionCompany>(); 
     foreach (var APIProductionCompany in Movie.ProductionCompanies) 
     { 
      var DBProductionCompany = DBProductionCompanies.Where(My => My.ID == APIProductionCompany.Id).FirstOrDefault(); 
      if (DBProductionCompany == null) 
      { 
       DBProductionCompany = new Entities.TMDB.ProductionCompany(); 
      } 
      DBProductionCompany.ID = APIProductionCompany.Id; 
      DBProductionCompany.Name = APIProductionCompany.Name; 
      DBProductionCompany.Movies.Add(Movy); 
      Movy.ProductionCompanies.Add(DBProductionCompany); 
     } 
    } 

    if (Movie.ProductionCountries != null && Movie.ProductionCountries.Count > 0) 
    { 
     //Retrieve ProductionCountries 
     var APIProductionCountryIds = Movie.ProductionCountries.Select(My => My.Iso_3166_1).ToList(); 
     var DBProductionCountries = Context.ProductionCountries.Where(My => APIProductionCountryIds.Contains(My.ISo_3166_1)).ToList(); 

     if (Movy.ProductionCountries == null) Movy.ProductionCountries = new List<Entities.TMDB.ProductionCountry>(); 
     foreach (var APIProductionCountry in Movie.ProductionCountries) 
     { 
      var DBProductionCountry = DBProductionCountries.Where(My => My.ISo_3166_1 == APIProductionCountry.Iso_3166_1).FirstOrDefault(); 
      if (DBProductionCountry == null) 
      { 
       DBProductionCountry = new Entities.TMDB.ProductionCountry(); 
      } 
      DBProductionCountry.ISo_3166_1 = APIProductionCountry.Iso_3166_1; 
      DBProductionCountry.Name = APIProductionCountry.Name; 
      DBProductionCountry.Movies.Add(Movy); 
      Movy.ProductionCountries.Add(DBProductionCountry); 
     } 
    } 


    Movy.Popularity = (decimal)Movie.Popularity; 
    Movy.Revenue = Movie.Revenue; 

    if (Movie.SpokenLanguages != null && Movie.SpokenLanguages.Count > 0) 
    { 
     //Retrieve SpokenLanguages 
     var APISpokenLanguageIds = Movie.SpokenLanguages.Select(My => My.Iso_639_1).ToList(); 
     var DBSpokenLanguages = Context.SpokenLanguages.Where(My => APISpokenLanguageIds.Contains(My.Iso_639_1)).ToList(); 

     if (Movy.SpokenLanguages == null) Movy.SpokenLanguages = new List<Entities.TMDB.SpokenLanguage>(); 
     foreach (var APISpokenLanguage in Movie.SpokenLanguages) 
     { 
      var DBSpokenLanguage = DBSpokenLanguages.Where(My => My.Iso_639_1 == APISpokenLanguage.Iso_639_1).FirstOrDefault(); 
      if (DBSpokenLanguage == null) 
      { 
       DBSpokenLanguage = new Entities.TMDB.SpokenLanguage(); 
      } 
      DBSpokenLanguage.Iso_639_1 = APISpokenLanguage.Iso_639_1; 
      DBSpokenLanguage.Name = APISpokenLanguage.Name; 
      DBSpokenLanguage.Movies.Add(Movy); 
      Movy.SpokenLanguages.Add(DBSpokenLanguage); 
     } 
    } 

    Movy.VoteAverage = (decimal) Movie.VoteAverage; 
    Movy.VoteCount = Movie.VoteCount; 

    if (Movie.Videos != null && Movie.Videos.Results != null && Movie.Videos.Results.Count > 0) 
    { 
     if (Movy.Videos == null) 
     { 
      Movy.Videos = new List<Entities.TMDB.Video>(); 
     } 
     foreach (var Video in Movie.Videos.Results) 
     { 
      var DBVideo = Movy.Videos.Where(My => My.ID == Video.Id).FirstOrDefault(); 

      if (DBVideo == null) 
      { 
       DBVideo = new Entities.TMDB.Video(); 
       Movy.Videos.Add(DBVideo); 
      } 

      DBVideo.ID = Video.Id; 
      DBVideo.Iso_639_1 = Video.Iso_639_1; 
      DBVideo.Name = Video.Name; 
      DBVideo.Site = Video.Site; 
      DBVideo.Type = Video.Type; 
      DBVideo.VideoKey = Video.Key; 

      DBVideo.Movy = Movy; 
      DBVideo.MovieID = Movy.ID; 
     } 
    } 

    //Similar Items 
    if (Movie.Similar != null && Movie.Similar.Results != null && Movie.Similar.Results.Count > 0) 
    { 
     foreach (var SimilarItem in Movie.Similar.Results) 
     { 
      DB.DBUtilities.Set.AddSimilarMoviesToContext(Movie.Id, SimilarItem.Id); 
     } 
    } 

    Movy.LastUpdated = DateTime.Now; 
    Context.SaveChanges(); 
    return Movy; 
} 

Dieser Code wobei dies bis zu 20% CPU verwenden, wenn gefordert ein Film. Ich verwende einen Kontext für eine Einfügung. Add() und DBSet.Local.Where (..) Methoden sind hier am teuersten. Wie kann ich den Code optimieren, um die CPU zu reduzieren?

Update: Auf Code-Profilierung fand ich DBSet.Local.Where (..) ist, wo die CPU auffrisst. Mein Grund, DBSet.Local.Where zu nennen, ist herauszufinden, ob ich dieses Objekt (Person) bereits hinzugefügt habe, damit ich es nicht wieder hinzufüge. Gedanken?

+0

Es sieht für mich wie Sie ein einzelnes 'DbContext' global Hand halten und es immer wieder wiederverwendet. Das ist schlecht. Sie sollten "neu" im lokalen Bereich arbeiten, kleine Mengen an Arbeit damit erledigen, "Speichern", dann "Entsorgen" und verwerfen, idealerweise mit einer 'using'-Anweisung und im * lokalen * Geltungsbereich behaltend. Diese Kontexte sind nicht dafür ausgelegt, langlebig zu sein. – spender

+0

Mit Lazy Loading, dieser Code muss Dutzende, möglicherweise mehr Abfragen pro einfügen. Lazy Loading und Leistung passen nicht gut zusammen. – spender

+0

Dies ist eine asp.net-Website. Ich habe einen langen Live-Kontext. aber ich benutze das nicht darin. Für jeden Film addorupdate-Aufruf wird ein neuer Kontext bereitgestellt. – Dmiller

Antwort

0

Diese Movies.Where(My => My.ID == Movie.Id).FirstOrDefault() kann durch Aufruf Movies.Find(Movie.Id) optimiert werden.

Sucht eine Entität mit den angegebenen Primärschlüsselwerten. Wenn eine Entität mit den angegebenen Primärschlüsselwerten im Kontext vorhanden ist, wird sie sofort zurückgegeben, ohne eine Anfrage an den Store zu stellen. https://msdn.microsoft.com/en-us/library/gg696418(v=vs.113).aspx

Ich sehe keine Optimierungen für die Add()