public Task AddTrackToAlbum(Album UpdatedAlbum)
 {
     throw new NotImplementedException();
 }
        /// <summary>
        /// Add a new track to an existing album in the In-Memory context, updating the related 
        /// entities and ensuring the navigation properties are correctly updated.
        /// </summary>
        /// <param name="UpdatedAlbum">The new track, encapsulated within an album</param>
        /// <returns>An instance of Task so the method is awaitable</returns>
        /// <remarks>
        /// This method introduces a bottleneck to the asynchronous processing that
        /// happens to get here.  All routines within this context are synchronous
        /// in nature because there are no methods that are called from them, such
        /// as List(T).Add methods that can be asynchronous.  
        /// <para>
        /// This lock, actually makes the locks in the DataHelper methods redundant,
        /// Because this entire thread has access locked with this one.  However
        /// There is no harm at all in leaving the other locks in place, should the
        /// application be extended in the future and allowing the other methods
        /// to be called from elsewhere.
        /// </para>
        /// <para>
        /// These methods all produce warning errors, complaining that they 
        /// "lacking await" keywords and will therefore execute synchronously.
        /// These could be removed by calling await Task.Delay(0) which would
        /// remove the warning message but provide no improvement to the 
        /// efficiency of the routines.
        /// </para>
        /// </remarks>
        public async Task AddTrackToAlbum(Album UpdatedAlbum)
        {
            //  Get the existing album
            //  get by Id
            var existingAlbum = this.Albums.FirstOrDefault(a => a.Id == UpdatedAlbum.Id);
            //  If not then check by artist Name and Album Title
            if (existingAlbum == null)
                existingAlbum = this.Albums.FirstOrDefault(a => a.Title == UpdatedAlbum.Title && a.Artist.Name == UpdatedAlbum.Artist.Name);

            //  Only process it if the ablum has been found.
            if (existingAlbum != null)
            {
                var albumIdx = this.Albums.IndexOf(existingAlbum);

                var newTrack = UpdatedAlbum.Tracks.FirstOrDefault();

                lock (_AlbumsLock)
                {
                    //  1.  Check if track already exists
                    var existingTrack = existingAlbum.Tracks.FirstOrDefault(t => t.Title.ToLowerInvariant() == newTrack.Title.ToLowerInvariant());
                    if (existingTrack != null)
                    {
                        //      1a. Update all the track related fields
                        //  Get the index of the track.
                        var idx = existingAlbum.Tracks.IndexOf(existingTrack);

                        //  Add the new track to the tracks collection and update the Id and album reference
                        //  The updated album contains only the one track, this needs a list
                        var updatedTrack = _helper.AddTracksToContext(this, UpdatedAlbum.Tracks, existingAlbum);
                        //  Now replace it in the Album tracks
                        existingAlbum.Tracks[idx] = updatedTrack[0];
                    }
                    else
                    {
                        //      1b. Add the track to the album
                        //  Add the new track to the tracks collection and update the Id and album reference
                        //  The updated album contains only the one track, this needs a list
                        var updatedTrack = _helper.AddTracksToContext(this, UpdatedAlbum.Tracks, existingAlbum);
                        //  now add it to the albums tracks
                        existingAlbum.Tracks.Add(updatedTrack[0]);
                    }

                    //  Add any new Genres to the existing ones, duplicates will be removed when the Genres are
                    //  updated by the AddGenresToContext routine.
                    foreach (var g in UpdatedAlbum.Genres)
                    {
                        var existingGenre = existingAlbum.Genres
                            .FirstOrDefault(gn => gn.Name == g.Name);
                        if (existingAlbum == null)
                            existingAlbum.Genres.Add(g);
                    }
                    //  3   Add each genre to the Genres collection, ensure navigation properties are updated
                    var updatedGenres = _helper.AddGenresToContext(this, UpdatedAlbum.Genres, existingAlbum);
                    existingAlbum.Genres = updatedGenres;

                    //  Replace the Album reference in the Artist, as it has been updated to ensure the
                    //  navigation properties are up to date.  It will find the artist, and the album too
                    //  so the album reference will be replaced.
                    var updatedArtist = _helper.AddArtistToContext(this, existingAlbum.Artist, existingAlbum);
                    //  update the reference to the artist in the existingAlbum
                    existingAlbum.Artist = updatedArtist;


                    //Finally replace the Album in the Albums collection
                    this.Albums[albumIdx] = existingAlbum;
                }
            }
        }
 public Task<Album> CreateAlbum(Album newAlbum)
 {
     throw new NotImplementedException();
 }
Beispiel #4
0
        /// <summary>
        /// Add the album to the Artist, and if necessary, to the AlbumIds as well.
        /// </summary>
        /// <param name="Artist">The Artist</param>
        /// <param name="Album">The album being added</param>
        /// <remarks>
        /// Only add an AlbumId if to the AlbumIds collection if it's not already there.
        /// It won't be if the its is a New Album being created, but there will be when 
        /// reloading the persisted data.
        /// </remarks>
        private void AddAlbumToArtist(Artist Artist, Album Album)
        {
            //  Add the Album to the albums collection
            Artist.Albums.Add(Album);

            //  Only add an AlbumId if to the AlbumIds collection if it's not already there.
            //  It won't be if the its is a New Album being created,
            //  but there will be when reloading the persisted data.
            if (!Artist.AlbumIds.Contains(Album.Id))
                Artist.AlbumIds.Add(Album.Id);
        }
        /// <summary>
        /// Adds a new album to the In-Memory context, updating the related entities.
        /// </summary>
        /// <param name="newAlbum">The Album to be Created and added to the context</param>
        /// <returns>The instance of the album created</returns>
        /// <remarks>
        /// This method introduces a bottleneck to the asynchronous processing that
        /// happens to get here.  All routines within this context are synchronous
        /// in nature because there are no methods that are called from them, such
        /// as List(T).Add methods that can be asynchronous.  
        /// <para>
        /// This lock, actually makes the locks in the DataHelper methods redundant,
        /// Because this entire thread has access locked with this one.  However
        /// There is no harm at all in leaving the other locks in place, should the
        /// application be extended in the future and allowing the other methods
        /// to be called from elsewhere.
        /// </para>
        /// <para>
        /// These methods all produce warning errors, complaining that they 
        /// "lacking await" keywords and will therefore execute synchronously.
        /// These could be removed by calling await Task.Delay(0) which would
        /// remove the warning message but provide no improvement to the 
        /// efficiency of the routines.
        /// </para>
        /// </remarks>
        public async Task<Album> CreateAlbum(Album newAlbum)
        {
            lock (_AlbumsLock)
            {

                //  1.  Calculate the new AlbumId and update the album
                newAlbum.Id = _helper.GenerateAlbumId(this);

                //  2.  Add the album ref to each track and add each to the Tracks collection
                //      and update the tracks collection to ensure the navigation properties are updated.
                var updatedTracks = _helper.AddTracksToContext(this, newAlbum.Tracks, newAlbum);
                newAlbum.Tracks = updatedTracks;

                //  3   Add each genre to the Genres collection, ensure navigation properties are updated
                var updatedGenres = _helper.AddGenresToContext(this, newAlbum.Genres, newAlbum);
                newAlbum.Genres = updatedGenres;

                //  4   Add the Artist to the Artist collection, ensure navigation properties are updated.
                var updatedArtist = _helper.AddArtistToContext(this, newAlbum.Artist, newAlbum);
                newAlbum.Artist = updatedArtist;

                //  5.  Add the album to the Albums collection
                this.Albums.Add(newAlbum);
            }
            return newAlbum;
        }
Beispiel #6
0
        /// <summary>
        /// Adds a new Artist to the Artists collection and updates the albums referenced
        /// </summary>
        /// <param name="UnitOfWork">In-Memory context</param>
        /// <param name="Artist">the New artist</param>
        /// <param name="Album">The Album it relates to</param>
        /// <returns>The New Artist</returns>
        /// <remarks>
        /// <para>
        /// Only add an AlbumId if to the AlbumIds collection if it's not already there.
        /// It won't be if the its is a New Album being created, but there will be when 
        /// reloading the persisted data.
        /// </para>
        /// <para>
        /// Concurrency:    
        /// </para>
        /// <Para>
        /// This routine provides a Monitor lock to ensure that only one instance of this
        /// can modify the Artists collection at a time.
        /// It locks from the point which a new Id is generated for the Artist being added
        /// and retains that until the Artist is added to the Genres collection.
        /// This type of lock is preferred to ensure the generated Id is updated within
        /// the Genres collection before any other thread can try and Add a Genre which 
        /// would require the Id for this one, which woudl be used in the GenerateId 
        /// methods.  This is to avoid duplicate Id's being generated.
        /// </Para>
        /// <para>
        /// This is a very course grained way of locking but is acceptible within this
        /// application as it is a Windows 8 store app, and not subjected to multiple
        /// users, only the individual threads within the application.  The performance
        /// hit should not be that noticable here.
        /// </para>
        /// </remarks>
        private Artist AddArtist(IUnitOfWork UnitOfWork, Artist Artist, Album Album)
        {
            //  
            lock (_ArtistLock)
            {
                //  Concurrency:  Lock between getting the Id and performing the update, as the
                //                  this new Id won't be availble for checking purposes by another
                //                  thread that is looking to add an Artist.  This should avoid the
                //                  possiblilties of duplicate Id's

                Artist.Albums = new List<Album>();

                //          i.  Generate ArtistId, if there isn'[t one already, will be reloading persisted data.
                if (Artist.Id == 0)
                    Artist.Id = GenerateArtistId(UnitOfWork);
                //          ii. Add album ref to Artist
                AddAlbumToArtist(Artist, Album);
                //          iii.Add Artist to Artists Collection
                UnitOfWork.Artists.Add(Artist);
            }
            return Artist;
        }
Beispiel #7
0
        /// <summary>
        /// Updates the Artist in the Artists collection.
        /// </summary>
        /// <param name="UnitOfWork">The In-Memory context</param>
        /// <param name="Artist">The artist to be updated</param>
        /// <param name="Album">The album</param>
        /// <returns>The Updated Artist</returns>
        /// <remarks>
        /// The update artist is returned so that it can replace the 
        /// Artist in the album, which means the navigation properties
        /// are up to date.
        /// <para>
        /// Concurrency:    
        /// </para>
        /// <Para>
        /// This routine provides a Monitor lock to ensure that only one instance of this
        /// can modify the Artists collection at a time.
        /// It locks from the point where the Genre to be updated is retrieved from 
        /// the Artist 
        /// and retains that until the Artist is updated in the Artists collection.
        /// This type of lock is preferred to ensure that no other updates to the Artist
        /// are possible while this update occurs.  
        /// </Para>
        /// <para>
        /// This is a very course grained way of locking but is acceptible within this
        /// application as it is a Windows 8 store app, and not subjected to multiple
        /// users, only the individual threads within the application.  The performance
        /// hit should not be that noticable here.
        /// </para>
        /// </remarks>
        private Artist UpdateArtist(IUnitOfWork UnitOfWork, Artist Artist, Album Album)
        {
            int idx = 0;

            lock (_ArtistLock)
            {
                //  Get the index of the Artist
                idx = UnitOfWork.Artists.FindIndex(a => a.Name == Artist.Name);
                //  Get the Artist
                var updatedArtist = UnitOfWork.Artists[idx];

                //  If Album exists in the retrieved Artist.
                var al = updatedArtist.Albums.FirstOrDefault(a => a.Id == Album.Id);
                if (al != null)
                {
                    //  The Album is found, so replace it
                    var alIdx = updatedArtist.Albums.IndexOf(al);
                    updatedArtist.Albums[alIdx] = Album;
                }
                else
                {
                    //  Album dosn't exist in the Artist.Albums collection, so just add it.
                    AddAlbumToArtist(updatedArtist, Album);
                }

                //  Replace the Artist in the Artists collection
                UnitOfWork.Artists[idx] = updatedArtist;
            }
            //  return the updated Artist
            return UnitOfWork.Artists[idx];
//            return updatedArtist;
        }
Beispiel #8
0
 /// <summary>
 /// Add the Artist to the In-Memory context.  The updated 
 /// Artist is returned to update the Album
 /// </summary>
 /// <param name="UnitOfWork">In-Memory context</param>
 /// <param name="Artist">The Artist to be updated</param>
 /// <param name="Album">The album reference</param>
 /// <returns>The updated Artist</returns>
 /// <remarks>
 /// <para>
 /// Only add an AlbumId if to the AlbumIds collection if it's not already there.
 /// It won't be if the its is a New Album being created, but there will be when 
 /// reloading the persisted data.
 /// </para>
 /// </remarks>
 public Artist AddArtistToContext(IUnitOfWork UnitOfWork, Artist Artist, Album Album)
 {
     //      4a  If exists, Add album reference to the Artist
     if (ArtistExists(UnitOfWork, Artist.Name))
     {
         var updatedArtist = UpdateArtist(UnitOfWork, Artist, Album);
         return updatedArtist;
     }
     else
     {
         //      4b  If doesn't exist, generate Artist Id
         var newArtist = AddArtist(UnitOfWork, Artist, Album);
         //          iv. Replace Artist to Album.Artist
         return Artist;
     }
 }
Beispiel #9
0
        /// <summary>
        /// Updates the Genre in the Genres collection.
        /// </summary>
        /// <param name="UnitOfWork">The In-Memory context</param>
        /// <param name="Genre">The Genre to be updated</param>
        /// <param name="Album">The album</param>
        /// <returns>The Updated Genre</returns>
        /// <remarks>
        /// <para>
        /// The update genre is returned so that it can replace the 
        /// genre in the album, which means the navigation properties
        /// are up to date.
        /// </para>
        /// <para>
        /// Only add an AlbumId if to the AlbumIds collection if it's not already there.
        /// It won't be if the its is a New Album being created, but there will be when 
        /// reloading the persisted data.
        /// </para>
        /// <para>
        /// Concurrency:    
        /// </para>
        /// <Para>
        /// This routine provides a Monitor lock to ensure that only one instance of this
        /// can modify the Genres collection at a time.
        /// It locks from the point where the Genre to be updated is retrieved from 
        /// the Genres 
        /// and retains that until the Genre is updated in the Genres collection.
        /// This type of lock is preferred to ensure that no other updates to the Genres
        /// is attempted while this update occurs.
        /// </Para>
        /// <para>
        /// This is a very course grained way of locking but is acceptible within this
        /// application as it is a Windows 8 store app, and not subjected to multiple
        /// users, only the individual threads within the application.  The performance
        /// hit should not be that noticable here.
        /// </para>
        /// </remarks>
        private Genre UpdateGenre(IUnitOfWork UnitOfWork, Genre Genre, Album Album)
        {
            //  TODO: Refactor this to use the concurrent collection.

            var idx = 0;

            lock (_GenreLock)
            {

                //  Get the index of the Genre
                idx = UnitOfWork.Genres.FindIndex(g => g.Name == Genre.Name);

                //  Get the Genre
                var updatedGenre = UnitOfWork.Genres[idx];

                //  If Album exists in the retrieved Genre.
                var al = updatedGenre.Albums.FirstOrDefault(a => a.Id == Album.Id);
                if (al != null)
                {
                    //  The Album is found, so replace it
                    var alIdx = updatedGenre.Albums.IndexOf(al);
                    updatedGenre.Albums[alIdx] = Album;
                }
                else
                {
                    //  Track dosn't exist in the Genres.Tracks collection, so just add it.
                    AddAlbumToGenre(updatedGenre, Album);
                }

                //  Replace the Genre in the Genres collection
                UnitOfWork.Genres[idx] = updatedGenre;
            }
            
            //  return the updated Genre
            return UnitOfWork.Genres[idx];
        }
Beispiel #10
0
        /// <summary>
        /// Adds a  new Genre to the Genres collection of the Domain model.  It 
        /// returns an instance of the Genre added so that it can be used elsewhere.
        /// This is standard coding for creating a new object.
        /// </summary>
        /// <param name="UnitOfWork">The In-Memory context</param>
        /// <param name="Genre">the new Genre</param>
        /// <param name="Album">The album the Genre relates to</param>
        /// <returns>The updated instance of the new Genre</returns>
        /// <remarks>
        /// Only add an AlbumId if to the AlbumIds collection if it's not already there.
        /// It won't be if the its is a New Album being created, but there will be when 
        /// reloading the persisted data.
        /// <para>
        /// Concurrency:    
        /// </para>
        /// <Para>
        /// This routine provides a Monitor lock to ensure that only one instance of this
        /// can modify the Genres collection at a time.
        /// It locks from the point which a new Id is generated for the Genre being added
        /// and retains that until the Genre is added to the Genres collection.
        /// This type of lock is preferred to ensure the generated Id is updated within
        /// the Genres collection before any other thread can try and Add a Genre which 
        /// would require the Id for this one, which woudl be used in the GenerateId 
        /// methods.  This is to avoid duplicate Id's being generated.
        /// </Para>
        /// <para>
        /// This is a very course grained way of locking but is acceptible within this
        /// application as it is a Windows 8 store app, and not subjected to multiple
        /// users, only the individual threads within the application.  The performance
        /// hit should not be that noticable here.
        /// </para>
        /// </remarks>
        private Genre AddGenre(IUnitOfWork UnitOfWork, Genre Genre, Album Album)
        {

            lock (_GenreLock)
            {
                Genre.Albums = new List<Album>();

                //  Concurrency:  Lock between getting the Id and performing the update, as the
                //                  this new Id won't be availble for checking purposes by another
                //                  thread that is looking to add a Genre.  This should avoid the
                //                  possiblilties of duplicate Id's

                //          i.  Generate GenreId, if there isn't one, will be if reloading persisted data.

                if (Genre.Id == 0)
                    Genre.Id = GenerateGenreId(UnitOfWork);
                //          ii. Add album ref to Genre
                AddAlbumToGenre(Genre, Album);
                //          iii.Add Genre to Genres Collection
                UnitOfWork.Genres.Add(Genre);
            }

            return Genre;
        }
Beispiel #11
0
 /// <summary>
 /// Add the Genres to the In-Memory context.  The complete collection of update
 /// genres is returned to update the Album
 /// </summary>
 /// <param name="UnitOfWork">In-Memory context</param>
 /// <param name="Genres">The genres to be updated</param>
 /// <param name="album">The album reference</param>
 /// <returns>The updated genres collection</returns>
 public List<Genre> AddGenresToContext(IUnitOfWork UnitOfWork, List<Genre> Genres, Album album)
 {
     var updatedGenres = new List<Genre>();
     //  3   Add each genre to the Genres collection
     foreach (var gn in Genres)
     {
         //      3a  If exists, Add album reference to the Genre
         if (GenreExists(UnitOfWork, gn.Name))
         {
             var updateGenre = UpdateGenre(UnitOfWork, gn, album);
             updatedGenres.Add(updateGenre);
         }
         else
         {
             //      3b  If doesn't exist, generate Genre Id
             var newGenre = AddGenre(UnitOfWork, gn, album);
             //          iv. Replace Genre to Album.Genres collection
             updatedGenres.Add(newGenre);
         }
     }
     return updatedGenres;
 }
Beispiel #12
0
        /// <summary>
        /// Updates the Track: New Id and Album, and adds to the Tracks Collection
        /// </summary>
        /// <param name="UnitOfWork">The instance of the in-memory context</param>
        /// <param name="Tracks">The track to be added</param>
        /// <param name="Album">The album the track belongs to</param>
        /// <returns>The updated track</returns>
        /// <remarks>
        /// This is a synchronous task because there are no waitiable operations either
        /// needed or so use of List(T) is OK.
        /// </remarks>
        public List<Track> AddTracksToContext(IUnitOfWork UnitOfWork, List<Track> Tracks, Album Album)
        {
            var updatedTracks = new List<Track>();      
            foreach (var tr in Tracks)
            {
                //  Generate the Track Id and update the track, if there isn't one already
                if (tr.Id == 0)
                    tr.Id = GenerateTrackId(UnitOfWork);
                //  Add the album reference to the track
                tr.Album = Album;
                tr.AlbumId = Album.Id;

                //  Process any playlist that might exist (none for a new album import).
                if (tr.Playlists.Count > 0)
                {
                    var updatedPlaylists = AddOrUpdatePlaylists(UnitOfWork, tr.Playlists, tr);
                    tr.Playlists = updatedPlaylists;
                }

                //  Add the track to the Tracks collection
                UnitOfWork.Tracks.Add(tr);
                //  Add the updated track to the returned list;
                updatedTracks.Add(tr);
            }
            return updatedTracks;
        }