/// <summary>
        /// Adds a Restriction to a Product's complementary Product.
        /// </summary>
        /// <param name="addRestrictionToProductComponentMV">AddRestrictionToProductComponentModelView containing the data of the Restriction instance being added.</param>
        /// <returns>GetProductModelView with updated Product information.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when either of the Products could not be found.</exception>
        public GetProductModelView addRestrictionToProductComponent(AddComponentRestrictionModelView addRestrictionToProductComponentMV)
        {
            ProductRepository productRepository = PersistenceContext.repositories().createProductRepository();
            Product           parentProduct     = productRepository.find(addRestrictionToProductComponentMV.fatherProductId);

            if (parentProduct == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, addRestrictionToProductComponentMV.fatherProductId));
            }

            //filter product's components rather than accessing the repository
            Product childProduct = parentProduct.components
                                   .Where(component => component.complementaryProduct.Id == addRestrictionToProductComponentMV.childProductId)
                                   .Select(component => component.complementaryProduct).SingleOrDefault();

            if (childProduct == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, addRestrictionToProductComponentMV.childProductId));
            }

            Algorithm algorithm = new AlgorithmFactory().createAlgorithm(addRestrictionToProductComponentMV.restriction.algorithmId);

            if (addRestrictionToProductComponentMV.restriction.inputValues != null)
            {
                algorithm.setInputValues(InputValueModelViewService.toDictionary(addRestrictionToProductComponentMV.restriction.inputValues));
            }
            algorithm.ready();
            Restriction restriction = new Restriction(addRestrictionToProductComponentMV.restriction.description, algorithm);

            parentProduct.addComplementaryProductRestriction(childProduct, restriction);
            parentProduct = productRepository.update(parentProduct);
            return(ProductModelViewService.fromEntity(parentProduct));
        }
        /// <summary>
        /// Adds a Restriction to a Product's Material.
        /// </summary>
        /// <param name="addRestrictionModelView">AddRestrictionToProductMaterialModelView containing the data of the Restriction instance being added.</param>
        /// <returns>GetProductModelView with updated Product information.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when the Product or the Material could not be found.</exception>
        public GetProductModelView addRestrictionToProductMaterial(AddProductMaterialRestrictionModelView addRestrictionModelView)
        {
            ProductRepository productRepository = PersistenceContext.repositories().createProductRepository();
            Product           product           = productRepository.find(addRestrictionModelView.productId);

            if (product == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, addRestrictionModelView.productId));
            }

            //filter product's materials rather than accessing the repository
            Material material = product.productMaterials
                                .Where(productMaterial => productMaterial.materialId == addRestrictionModelView.materialId)
                                .Select(productMaterial => productMaterial.material).SingleOrDefault();

            if (material == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_MATERIAL_BY_ID, addRestrictionModelView.materialId));
            }

            Algorithm algorithm = new AlgorithmFactory().createAlgorithm(addRestrictionModelView.restriction.algorithmId);

            if (addRestrictionModelView.restriction.inputValues != null)
            {
                algorithm.setInputValues(InputValueModelViewService.toDictionary(addRestrictionModelView.restriction.inputValues));
            }
            algorithm.ready();
            Restriction restriction = new Restriction(addRestrictionModelView.restriction.description, algorithm);

            product.addMaterialRestriction(material, restriction);
            product = productRepository.update(product);
            return(ProductModelViewService.fromEntity(product));
        }
        /// <summary>
        /// Adds a Restriction to a Product's Measurement.
        /// </summary>
        /// <param name="addRestrictionToProductMeasurementMV">AddRestrictionToProductMeasurementModelView with the Product's and Measurement's persistence identifiers
        /// as well as the Restriction's data.</param>
        /// <returns>GetProductModelView with updated Product information.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when either the Product or the Measurement could not be found.</exception>
        public GetProductModelView addRestrictionToProductMeasurement(AddMeasurementRestrictionModelView addRestrictionToProductMeasurementMV)
        {
            ProductRepository productRepository = PersistenceContext.repositories().createProductRepository();

            Product product = productRepository.find(addRestrictionToProductMeasurementMV.productId);

            if (product == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, addRestrictionToProductMeasurementMV.productId));
            }

            Measurement measurement = product.productMeasurements
                                      .Where(pm => pm.measurementId == addRestrictionToProductMeasurementMV.measurementId).Select(pm => pm.measurement).SingleOrDefault();

            if (measurement == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_MEASUREMENT_BY_ID, addRestrictionToProductMeasurementMV.measurementId));
            }

            Algorithm algorithm = new AlgorithmFactory().createAlgorithm(addRestrictionToProductMeasurementMV.restriction.algorithmId);

            if (addRestrictionToProductMeasurementMV.restriction.inputValues != null)
            {
                algorithm.setInputValues(InputValueModelViewService.toDictionary(addRestrictionToProductMeasurementMV.restriction.inputValues));
            }
            algorithm.ready();
            Restriction restriction = new Restriction(addRestrictionToProductMeasurementMV.restriction.description, algorithm);

            product.addMeasurementRestriction(measurement, restriction);

            product = productRepository.update(product);

            return(ProductModelViewService.fromEntity(product));
        }