public CommandResult Execute(ICommandInfo commandInfo)
        {
            var saveInfo = (SaveEntityCommandInfo)commandInfo;

            if (saveInfo.Entity == null)
            {
                throw new ClientException("Invalid SaveEntityCommand argument: Entity is not set.");
            }

            // We need to check delete permissions before actually deleting items
            // and update items before AND after they are updated.
            var genericRepository = _genericRepositories.GetGenericRepository(saveInfo.Entity);

            var updateDeleteItems = ConcatenateNullable(saveInfo.DataToDelete, saveInfo.DataToUpdate);

            if (updateDeleteItems != null)
            {
                if (!_serverCommandsUtility.CheckAllItemsWithinFilter(updateDeleteItems, typeof(Common.RowPermissionsWriteItems), genericRepository))
                {
                    _persistenceTransaction.DiscardOnDispose();
                    Guid?missingId;
                    if (_serverCommandsUtility.MissingItemId(saveInfo.DataToDelete, genericRepository, out missingId))
                    {
                        throw new ClientException($"Deleting a record that does not exist in database. DataStructure={saveInfo.Entity}, ID={missingId}");
                    }
                    else if (_serverCommandsUtility.MissingItemId(saveInfo.DataToUpdate, genericRepository, out missingId))
                    {
                        throw new ClientException($"Updating a record that does not exist in database. DataStructure={saveInfo.Entity}, ID={missingId}");
                    }
                    else
                    {
                        throw new UserException("You are not authorized to write some or all of the provided data. Insufficient permissions to modify the existing data.", $"DataStructure:{saveInfo.Entity},Validation:RowPermissionsWrite");
                    }
                }
            }

            genericRepository.Save(saveInfo.DataToInsert, saveInfo.DataToUpdate, saveInfo.DataToDelete, true);

            var insertUpdateItems = ConcatenateNullable(saveInfo.DataToInsert, saveInfo.DataToUpdate);

            // We rely that this call will only use IDs of the items, because other data might be dirty.
            if (insertUpdateItems != null)
            {
                if (!_serverCommandsUtility.CheckAllItemsWithinFilter(insertUpdateItems, typeof(Common.RowPermissionsWriteItems), genericRepository))
                {
                    _persistenceTransaction.DiscardOnDispose();
                    throw new UserException("You are not authorized to write some or all of the provided data. Insufficient permissions to apply the new data.", $"DataStructure:{saveInfo.Entity}.");
                }
            }

            return(new CommandResult
            {
                Message = "Command executed",
                Success = true
            });
        }
        public ProcessingResult ExecuteInner(IList <ICommandInfo> commands, Guid executionId)
        {
            var authorizationMessage = _authorizationManager.Authorize(commands);

            if (!string.IsNullOrEmpty(authorizationMessage))
            {
                return new ProcessingResult
                       {
                           UserMessage   = authorizationMessage,
                           SystemMessage = authorizationMessage,
                           Success       = false
                       }
            }
            ;

            var commandResults = new List <CommandResult>();
            var stopwatch      = Stopwatch.StartNew();

            foreach (var commandInfo in commands)
            {
                try
                {
                    _logger.Trace("Executing command {0}.", commandInfo);

                    var implementations = _commandRepository.GetImplementations(commandInfo.GetType());

                    if (!implementations.Any())
                    {
                        throw new FrameworkException(string.Format(CultureInfo.InvariantCulture,
                                                                   "Cannot execute command \"{0}\". There are no command implementations loaded that implement the command.", commandInfo));
                    }

                    if (implementations.Count() > 1)
                    {
                        throw new FrameworkException(string.Format(CultureInfo.InvariantCulture,
                                                                   "Cannot execute command \"{0}\". It has more than one implementation registered: {1}.", commandInfo, String.Join(", ", implementations.Select(i => i.GetType().Name))));
                    }

                    var commandImplementation = implementations.Single();
                    _logger.Trace("Executing implementation {0}.", commandImplementation.GetType().Name);

                    var commandObserversForThisCommand = _commandObservers.GetImplementations(commandInfo.GetType());
                    stopwatch.Restart();

                    foreach (var commandObeserver in commandObserversForThisCommand)
                    {
                        commandObeserver.BeforeExecute(commandInfo);
                        _performanceLogger.Write(stopwatch, () => "CommandObeserver.BeforeExecute " + commandObeserver.GetType().FullName);
                    }

                    CommandResult commandResult;
                    try
                    {
                        commandResult = commandImplementation.Execute(commandInfo);
                    }
                    finally
                    {
                        _performanceLogger.Write(stopwatch, () => "Command executed (" + commandImplementation + ": " + commandInfo + ").");
                    }
                    _logger.Trace("Execution result message: {0}", commandResult.Message);

                    if (commandResult.Success)
                    {
                        foreach (var commandObeserver in commandObserversForThisCommand)
                        {
                            commandObeserver.AfterExecute(commandInfo, commandResult);
                            _performanceLogger.Write(stopwatch, () => "CommandObeserver.AfterExecute " + commandObeserver.GetType().FullName);
                        }
                    }

                    commandResults.Add(commandResult);

                    if (!commandResult.Success)
                    {
                        _persistenceTransaction.DiscardOnDispose();

                        var systemMessage = "Command failed: " + commandImplementation + ", " + commandInfo + ".";
                        return(LogAndReturnError(commandResults, systemMessage + " " + commandResult.Message, systemMessage, commandResult.Message, null, commands, executionId));
                    }
                }
                catch (Exception ex)
                {
                    _persistenceTransaction.DiscardOnDispose();

                    if (ex is TargetInvocationException && ex.InnerException is RhetosException)
                    {
                        _logger.Trace(() => "Unwrapping exception: " + ex.ToString());
                        ex = ex.InnerException;
                    }

                    string userMessage   = null;
                    string systemMessage = null;

                    ex = _sqlUtility.InterpretSqlException(ex) ?? ex;

                    if (ex is UserException userException)
                    {
                        userMessage   = _localizer[userException.Message, userException.MessageParameters]; // TODO: Remove this code after cleaning the double layer of exceptions in the server response call stack.
                        systemMessage = userException.SystemMessage;
                    }
                    else if (ex is ClientException)
                    {
                        userMessage   = _clientExceptionUserMessage;
                        systemMessage = ex.Message;
                    }
                    else
                    {
                        userMessage   = null;
                        systemMessage = ErrorReporting.GetInternalServerErrorMessage(_localizer, ex);
                    }

                    return(LogAndReturnError(commandResults, "Command failed: " + commandInfo + ".", systemMessage, userMessage, ex, commands, executionId));
                }
            }

            return(new ProcessingResult
            {
                CommandResults = commandResults.ToArray(),
                Success = true,
                SystemMessage = null
            });
        }