diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index b0ce7bf7c6..2a904be0d9 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; using System; using System.Threading; using System.Threading.Tasks; @@ -33,5 +34,22 @@ namespace MediaBrowser.Controller.Persistence /// The key. /// Task{UserItemData}. UserItemData GetUserData(Guid userId, string key); + + /// + /// Return all user data associated with the given user + /// + /// + /// + IEnumerable GetAllUserData(Guid userId); + + /// + /// Save all user data associated with the given user + /// + /// + /// + /// + /// + Task SaveAllUserData(Guid userId, IEnumerable userData, CancellationToken cancellationToken); + } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 4e388b4b0e..92fdde60f4 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; @@ -117,6 +118,20 @@ namespace MediaBrowser.Server.Implementations.Persistence return PersistUserData(userId, key, userData, cancellationToken); } + public Task SaveAllUserData(Guid userId, IEnumerable userData, CancellationToken cancellationToken) + { + if (userData == null) + { + throw new ArgumentNullException("userData"); + } + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + + return PersistAllUserData(userId, userData, cancellationToken); + } + /// /// Persists the user data. /// @@ -188,6 +203,79 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + /// + /// Persist all user data for the specified user + /// + /// + /// + /// + /// + private async Task PersistAllUserData(Guid userId, IEnumerable userData, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + foreach (var userItemData in userData) + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate)"; + + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating; + cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played; + cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount; + cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; + cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; + cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; + + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + } + } + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + _logger.ErrorException("Failed to save user data:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + _writeLock.Release(); + } + } + /// /// Gets the user data. /// @@ -227,25 +315,72 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (reader.Read()) { - if (!reader.IsDBNull(0)) - { - userData.Rating = reader.GetDouble(0); - } + ReadRow(reader, ref userData); + } + } + + return userData; + } + } + + /// + /// Return all user-data associated with the given user + /// + /// + /// + public IEnumerable GetAllUserData(Guid userId) + { + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } - userData.Played = reader.GetBoolean(1); - userData.PlayCount = reader.GetInt32(2); - userData.IsFavorite = reader.GetBoolean(3); - userData.PlaybackPositionTicks = reader.GetInt64(4); + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,key from userdata where userId=@userId"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - if (!reader.IsDBNull(5)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var userData = new UserItemData { - userData.LastPlayedDate = reader.GetDateTime(5).ToUniversalTime(); - } + UserId = userId, + }; + ReadRow(reader, ref userData); + userData.Key = reader.GetString(6); + yield return userData; } } - return userData; } + + } + + /// + /// Read a row from the specified reader into the provided userData object + /// + /// + /// + private static void ReadRow(IDataReader reader, ref UserItemData userData) + { + if (!reader.IsDBNull(0)) + { + userData.Rating = reader.GetDouble(0); + } + + userData.Played = reader.GetBoolean(1); + userData.PlayCount = reader.GetInt32(2); + userData.IsFavorite = reader.GetBoolean(3); + userData.PlaybackPositionTicks = reader.GetInt64(4); + + if (!reader.IsDBNull(5)) + { + userData.LastPlayedDate = reader.GetDateTime(5).ToUniversalTime(); + } + } ///