/// <summary> /// Creates a TvBroadcastListing /// </summary> /// <param name="importTag"></param> /// <param name="channelSource"></param> /// <param name="info"></param> /// <returns></returns> public TvProgramBroadCastListing AddBroadcastListing(TvProgramBroadCastListingImport importTag, TvChannelListingSource channelSource, IAddTvBroadCastListingInfo info) { // check if this import's going to violate the PK by trying to import duplicate Listings (on the same ImportId) if (CheckForViolatedPK(importTag, channelSource, info) != null) throw new TvBroadCastListingAlreadyExistsException( string.Format( "An item with that PK (import, channel, startat) {{{0}, {1}, {2}}} already exists", importTag.TvProgramBroadCastListingImportId, channelSource.TvChannelId, info.StartAt ) ); // clean up any whitespace on the text fields and replace as nulls where possible info.ProgramTitle = info.ProgramTitle.Trim(); info.EpisodeTitle = string.IsNullOrWhiteSpace(info.EpisodeTitle) ? null : info.EpisodeTitle.Trim(); info.EpisodeDescription = string.IsNullOrWhiteSpace(info.EpisodeDescription) ? null : info.EpisodeDescription.Trim(); // try and find or generate program information from this listing TvProgram program = GetOrCreateTvProgramFromListingInfo(info); // try and find or generate episode information from this listing TvProgramEpisode episode = GetOrCreateTvProgramEpisodeFromListingInfo(program, info); // if we don't have an EndDate we can't create a listing if (info.EndAt == null || info.StartAt == info.EndAt) return null; // see if there's an existing listing for this channel with these exact times var existing = FindExistingListing(channelSource, info.StartAt, info.EndAt.Value); if (existing != null) { // check if it's the same in every way except the importer if( // TvChannelId, StartAt, EndAt, Superceded==false are done by the DB existing.ProgramTitle == info.ProgramTitle && existing.EpisodeTitle == info.EpisodeTitle && existing.EpisodeDescription == info.EpisodeDescription && existing.TvProgramId == program.TvProgramId && existing.TvProgramEpisodeId == episode?.TvProgramEpisodeId && existing.Attributes == info.Attributes ) { // already an exact match, return that instead return existing; } } // create and add the new listing var newItem = new TvProgramBroadCastListing { TvProgramBroadCastListingImportId = importTag.TvProgramBroadCastListingImportId, TvChannelId = channelSource.TvChannelId, StartAt = info.StartAt, EndAt = info.EndAt, ProgramTitle = info.ProgramTitle, EpisodeTitle = info.EpisodeTitle, EpisodeDescription = info.EpisodeDescription, TvProgramId = program?.TvProgramId, TvProgramEpisodeId = episode?.TvProgramEpisodeId, Attributes = info.Attributes, Superceded = false }; TvListings.Add(newItem); // if we had an existing item that wasn't an exact match we mark it as superceded since we've just added a new one if (existing != null) { existing.Superceded = true; TvListings.Update(existing); } // return the new item we just made return newItem; }
protected TvProgramEpisode GetOrCreateTvProgramEpisodeFromListingInfo(TvProgram program, IAddTvBroadCastListingInfo info) { TvProgramEpisode episode; // first check if our new info has both series and episode number if (info.SeriesNumber.HasValue && info.EpisodeNumber.HasValue) { // check in the database for matching ProgramId, SeriesNumber, EpisodeNumber - that's a definitive link episode = FindExistingEpisodeByNumber(program, info.SeriesNumber, info.EpisodeNumber); if ( episode == null // nothing found at all || episode.EpisodeTitle != info.EpisodeTitle // an in-exact match which we'll duplicate || episode.EpisodeDescription != info.EpisodeDescription ) { // create one with this info and save it episode = new TvProgramEpisode { TvProgram = program, EpisodeTitle = info.EpisodeTitle, EpisodeDescription = info.EpisodeDescription, SeriesNumber = info.SeriesNumber, EpisodeNumber = info.EpisodeNumber }; TvEpisodes.Add(episode); } } // If the series and episode aren't both set check if the episodetitle is set else { // if it is, check for an exact match on episodetitle and episodedescription episode = FindExistingEpisodeByDescription(program, info.EpisodeTitle, info.EpisodeDescription); if ( episode == null // nothing found at all || episode.SeriesNumber != info.SeriesNumber // an in-exact match which we'll duplicate || episode.EpisodeNumber != info.EpisodeNumber // an in-exact match which we'll duplicate ) { // create a new one and save it episode = new TvProgramEpisode { TvProgram = program, EpisodeTitle = info.EpisodeTitle, EpisodeDescription = info.EpisodeDescription, SeriesNumber = info.SeriesNumber, EpisodeNumber = info.EpisodeNumber }; TvEpisodes.Add(episode); } } return episode; }
protected TvProgram GetOrCreateTvProgramFromListingInfo(IAddTvBroadCastListingInfo info) { // find or create a TvProgram with the same Title. // This is overly eager to match and should be comparing previous broadcasts on this channel or from this source maybe. var program = FindExistingProgramByTitle(info.ProgramTitle); if (program == null) { // no program found - create a new one program = new TvProgram { ProgramTitle = info.ProgramTitle }; TvPrograms.Add(program); } return program; }
/// <summary> /// Checks for an exact PK match on local changes only /// </summary> /// <param name="importTag"></param> /// <param name="channelSource"></param> /// <param name="info"></param> /// <returns></returns> protected TvProgramBroadCastListing CheckForViolatedPK(TvProgramBroadCastListingImport importTag, TvChannelListingSource channelSource, IAddTvBroadCastListingInfo info) { // in-memory dupe detection to stop duplicate PKs generated by broken feed / import processes var local = ChangeTracker.Entries<TvProgramBroadCastListing>() .SingleOrDefault(x => x.Property(y => y.TvProgramBroadCastListingImportId).CurrentValue == importTag.TvProgramBroadCastListingImportId && x.Property(y => y.TvChannelId).CurrentValue == channelSource.TvChannelId && x.Property(y => y.StartAt).CurrentValue == info.StartAt ); if (local != null) return local.Entity; // we don't need to check the database here because this TvProgramBroadCastListingImportId has been created by this thread return null; }