Я использую следующий код для вставки или обновления объекта.Почему сборщик мусора не собирает объекты dbcontext
public static void AddOrUpdate(this TMDbLib.Objects.Movies.Movie Movie)
{
//Check for duplicate items on every add() within foreach or for
if (Movie == null)
return;
if (string.IsNullOrEmpty(Movie.Title))
return;
//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;
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
if (Movy == null)
{
Movy = new Movy();
Movy.UrlTag = AspExtension.AspTools.StringHelper.Slugify(Movie.Title, MaxLength: 50);
Movy = AdditionalContext.Movies.Add(Movy);
}
else
{
}
Movy.ImdbID = IMDBID;
Movy.ID = Movie.Id;
AspExtension.AspTools.StringHelper.MapObjects(Movie, Movy);
Movy.Adult = Movie.Adult ? 1 : 0;
Movy.Budget = Movie.Budget;
Movy.Popularity = (decimal)Movie.Popularity;
Movy.Revenue = Movie.Revenue;
Movy.VoteAverage = (decimal)Movie.VoteAverage;
Movy.VoteCount = Movie.VoteCount;
Movy.HomePage = Movie.Homepage;
Movy.LastUpdated = DateTime.Now;
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
//Small fields and everything is saved here.
}
//Alternative title
if (Movie.AlternativeTitles != null && Movie.AlternativeTitles.Titles != null && Movie.AlternativeTitles.Titles.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
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;
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
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.
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve genres
var APIGenreIds = Movie.Genres.Select(My => My.Id).ToList();
var DBGenres = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
//One to many relationship. Check and add.
if (Movie.Images != null && Movie.Images.Posters.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
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;
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.Images != null && Movie.Images.Backdrops.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
if (Movy.Images == null) Movy.Images = new List<Entities.TMDB.Image>();
foreach (var APIImage in Movie.Images.Backdrops)
{
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 = "Backdrop";
DBImage.VoteAverage = (decimal)APIImage.VoteAverage;
DBImage.VoteCount = APIImage.VoteCount;
DBImage.Width = APIImage.Width;
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.Keywords != null && Movie.Keywords.Keywords != null & Movie.Keywords.Keywords.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve Keywords
var APIKeywordIds = Movie.Keywords.Keywords.Select(My => My.Id).ToList();
var DBKeywords = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
//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)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve Casts
var APICastIds = Movie.Credits.Cast.Select(My => My.Id).ToList(); //Person ids
var DBPersons = AdditionalContext.Persons.Where(My => APICastIds.Contains(My.ID)).ToList();
var DBMovie_Casts = AdditionalContext.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 = AdditionalContext.Persons.Local.Where(My => My.ID == APICast.Id).FirstOrDefault();
if (LocalDBPerson == null)
{
DBPerson = new Entities.TMDB.Person();
DBPerson.ID = APICast.Id;
DBPerson = AdditionalContext.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);
AdditionalContext.SaveChanges();
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.Credits != null && Movie.Credits.Crew != null && Movie.Credits.Crew.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve Crews
var APICrewIds = Movie.Credits.Crew.Select(My => My.Id).ToList();
var DBPersons = AdditionalContext.Persons.Where(My => APICrewIds.Contains(My.ID)).ToList();
var DBMovie_Crews = AdditionalContext.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 (AdditionalContext.Persons.Local.Where(My => My.ID == APICrew.Id).FirstOrDefault() == null)
{
DBPerson = new Entities.TMDB.Person();
DBPerson.ID = APICrew.Id;
AdditionalContext.Persons.Add(DBPerson);
}
else
{
DBPerson = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
//Many to many, just like genres
if (Movie.ProductionCompanies != null && Movie.ProductionCompanies.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve ProductionCompanies
var APIProductionCompanyIds = Movie.ProductionCompanies.Select(My => My.Id).ToList();
var DBProductionCompanies = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.ProductionCountries != null && Movie.ProductionCountries.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve ProductionCountries
var APIProductionCountryIds = Movie.ProductionCountries.Select(My => My.Iso_3166_1).ToList();
var DBProductionCountries = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.SpokenLanguages != null && Movie.SpokenLanguages.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
//Retrieve SpokenLanguages
var APISpokenLanguageIds = Movie.SpokenLanguages.Select(My => My.Iso_639_1).ToList();
var DBSpokenLanguages = AdditionalContext.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);
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
if (Movie.Videos != null && Movie.Videos.Results != null && Movie.Videos.Results.Count > 0)
{
using (var AdditionalContext = new TMDB())
{
var Movy = AdditionalContext.Movies.Find(Movie.Id);
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;
}
AdditionalContext.SaveChanges();
AdditionalContext.Entry(Movy).State = System.Data.Entity.EntityState.Detached;
AdditionalContext.Dispose();
}
}
//Similar Items
if (Movie.Similar != null && Movie.Similar.Results != null && Movie.Similar.Results.Count > 0)
{
var SimilarItems = Movie.Similar.Results.Select(My => My.Id);
using (var AdditionalContext = new TMDB())
{
var DBSimilarItems = AdditionalContext.SimilarItems.Where(My => My.MovieID1 == Movie.Id && SimilarItems.Contains(My.MovieID2)).ToList();
var SimilarItemsToBeAdded = new List<SimilarItem>();
foreach (var SimilarItem in Movie.Similar.Results)
{
var Item = DBSimilarItems.Where(My => My.MovieID1 == Movie.Id && My.MovieID2 == SimilarItem.Id).FirstOrDefault();
if (Item == null)
{
Item = AdditionalContext.SimilarItems.Local.Where(My => My.MovieID1 == Movie.Id && My.MovieID2 == SimilarItem.Id).FirstOrDefault();
if (Item == null)
{
Item = new SimilarItem();
Item.MovieID1 = Movie.Id;
Item.MovieID2 = SimilarItem.Id;
SimilarItemsToBeAdded.Add(Item);
}
}
}
if (SimilarItemsToBeAdded.Count > 0)
AdditionalContext.SimilarItems.AddRange(SimilarItemsToBeAdded);
AdditionalContext.SaveChanges();
AdditionalContext.Dispose();
}
}
}
Этот метод вызывается из чего-то вроде
for (int i = 0; i < MovieIds.Count; i++)
{
//Get from api
//Call AddOrUpdate
}
Контекст или какой-либо объект не будет возвращен за пределами метода. Таким образом, никакой объект не ссылается вне метода. Но если я продолжу цикл, мне нужно использовать 2 ГБ или память в какой-то момент.
При проверке выясняется, что объекты не удаляются из памяти. Хотя я использовал новые контексты в рамках использования блоков. Почему сборщик мусора не собирает эти объекты. Также попытался GC.Collect(), но ничего не изменилось. Что я делаю не так?
Обновленный код:
Я думаю, используя метод расширения был вопрос. Я хотел бы знать, что именно и как именно он фиксируется, но следующий код проверил память утечки
public static class ApiToDB
{
public static void AddOrUpdateMovie(TMDbLib.Objects.Movies.Movie Movie)
{
//Check for duplicate items on every add() within foreach or for
if (Movie == null)
return;
if (string.IsNullOrEmpty(Movie.Title))
return;
AddOrUpdateMovieBase(Movie);
AddOrUpdateAlternativeTitles(Movie);
AddOrUpdateGeneres(Movie);
AddOrUpdatePosterImages(Movie);
AddOrUpdateBackDropImages(Movie);
AddOrUpdateKeywords(Movie);
AddOrUpdateCast(Movie);
AddOrUpdatCrew(Movie);
AddOrUpdatCrew(Movie);
AddOrUpdateProductionCompanies(Movie);
AddOrUpdateProductionCountries(Movie);
AddOrUpdateSpokenLanguages(Movie);
AddOrUpdateVideos(Movie);
AddOrUpdateSimilarItems(Movie);
}
}
«Почему сборщик мусора не собирает эти объекты» - какие объекты? контексты? –
Если вы хотите найти утечку памяти, тогда профайлер памяти - ваш лучший друг. Но ваш метод выглядит как кошмар. Почему бы не создать * single * context вне метода * и * 'for' loop и использовать его во время процедуры добавления/обновления? Кроме того, 'AddOrUpdate' определенно должен быть разбит на число небольших методов. – Dennis
По объектам я имел в виду Dbcontext.movy и его дети – Dmiller