public IProperties ConvertProperties(IDictionary <string, object> properties, IObjectType type, HashSet <Updatability> updatabilityFilter)
        {
            // check input
            if (properties == null)
            {
                return(null);
            }

            // get the type
            if (type == null)
            {
                object typeIdObject;
                if (!properties.TryGetValue(PropertyIds.ObjectTypeId, out typeIdObject))
                {
                    throw new ArgumentException("Type or type property must be set!");
                }

                string typeId = typeIdObject as string;
                if (typeId == null)
                {
                    throw new ArgumentException("Type or type property must be set!");
                }

                type = session.GetTypeDefinition(typeId);
            }

            Properties result = new Properties();

            // the big loop
            foreach (KeyValuePair <string, object> property in properties)
            {
                string id    = property.Key;
                object value = property.Value;

                if (value is IProperty)
                {
                    IProperty p = (IProperty)value;
                    if (id != p.Id)
                    {
                        throw new ArgumentException("Property id mismatch: '" + id + "' != '" + p.Id + "'!");
                    }
                    value = (p.PropertyDefinition.Cardinality == Cardinality.Single ? p.FirstValue : p.Values);
                }

                // get the property definition
                IPropertyDefinition definition = type[id];
                if (definition == null)
                {
                    throw new ArgumentException("Property +'" + id + "' is not valid for this type!");
                }

                // check updatability
                if (updatabilityFilter != null)
                {
                    if (!updatabilityFilter.Contains(definition.Updatability))
                    {
                        continue;
                    }
                }

                PropertyData propertyData = new PropertyData(definition.PropertyType);
                propertyData.Id = id;

                // single and multi value check
                if (value == null)
                {
                    propertyData.Values = null;
                }
                else if (value is IList)
                {
                    if (definition.Cardinality != Cardinality.Multi)
                    {
                        throw new ArgumentException("Property '" + id + "' is not a multi value property!");
                    }

                    IList valueList = (IList)value;

                    // check if the list is homogeneous and does not contain null values
                    foreach (object o in valueList)
                    {
                        if (o == null)
                        {
                            throw new ArgumentException("Property '" + id + "' contains null values!");
                        }

                        propertyData.AddValue(o);
                    }
                }
                else
                {
                    if (definition.Cardinality != Cardinality.Single)
                    {
                        throw new ArgumentException("Property '" + id + "' is not a single value property!");
                    }

                    propertyData.AddValue(value);
                }

                result.AddProperty(propertyData);
            }

            return(result);
        }
        /// <inheritdoc/>
        public virtual IProperties ConvertProperties(IDictionary <string, object> properties, IObjectType type, ICollection <ISecondaryType> secondaryTypes, ISet <Updatability> updatabilityFilter)
        {
            // check input
            if (properties == null)
            {
                return(null);
            }

            // get the type
            if (type == null)
            {
                object typeIdObject;
                if (!properties.TryGetValue(PropertyIds.ObjectTypeId, out typeIdObject))
                {
                    throw new ArgumentException("Type or type property must be set!");
                }

                string typeId = typeIdObject as string;
                if (typeId == null)
                {
                    throw new ArgumentException("Type or type property must be set!");
                }

                type = session.GetTypeDefinition(typeId);
            }

            // get secondary types
            ICollection <ISecondaryType> allSecondaryTypes = null;
            object secondaryTypeIds;

            properties.TryGetValue(PropertyIds.SecondaryObjectTypeIds, out secondaryTypeIds);
            if (secondaryTypeIds is IList <string> )
            {
                allSecondaryTypes = new List <ISecondaryType>();

                foreach (string secondaryTypeId in (secondaryTypeIds as IList <string>))
                {
                    if (!(secondaryTypeId is string))
                    {
                        throw new ArgumentException("Secondary types property contains an invalid entry: "
                                                    + secondaryTypeId);
                    }

                    IObjectType secondaryType = session.GetTypeDefinition(secondaryTypeId.ToString());
                    if (!(secondaryType is ISecondaryType))
                    {
                        throw new ArgumentException(
                                  "Secondary types property contains a type that is not a secondary type: " + secondaryTypeId);
                    }

                    allSecondaryTypes.Add((ISecondaryType)secondaryType);
                }
            }

            if (secondaryTypes != null && allSecondaryTypes == null)
            {
                allSecondaryTypes = secondaryTypes;
            }

            Properties result = new Properties();

            // the big loop
            foreach (KeyValuePair <string, object> property in properties)
            {
                string id    = property.Key;
                object value = property.Value;

                if (value is IProperty)
                {
                    IProperty p = (IProperty)value;
                    if (id != p.Id)
                    {
                        throw new ArgumentException("Property id mismatch: '" + id + "' != '" + p.Id + "'!");
                    }
                    value = (p.PropertyDefinition.Cardinality == Cardinality.Single ? p.FirstValue : p.Values);
                }

                // get the property definition
                IPropertyDefinition definition = type[id];
                if (definition == null && allSecondaryTypes != null)
                {
                    foreach (ISecondaryType secondaryType in allSecondaryTypes)
                    {
                        if (secondaryType.PropertyDefinitions != null)
                        {
                            foreach (IPropertyDefinition propertyDefinition in secondaryType.PropertyDefinitions)
                            {
                                if (propertyDefinition.Id == id)
                                {
                                    definition = propertyDefinition;
                                    break;
                                }
                            }
                            if (definition != null)
                            {
                                break;
                            }
                        }
                    }
                    if (definition == null)
                    {
                        throw new ArgumentException("Property +'" + id + "' is not valid for this type!");
                    }
                }

                // check updatability
                if (updatabilityFilter != null)
                {
                    if (definition.Updatability.HasValue && !updatabilityFilter.Contains(definition.Updatability.Value))
                    {
                        continue;
                    }
                }

                PropertyData propertyData = new PropertyData(definition.PropertyType);
                propertyData.Id = id;

                // single and multi value check
                if (value == null)
                {
                    propertyData.Values = null;
                }
                else if (value is IList)
                {
                    if (definition.Cardinality != Cardinality.Multi)
                    {
                        throw new ArgumentException("Property '" + id + "' is not a multi value property!");
                    }

                    IList valueList = (IList)value;

                    // check if the list is homogeneous and does not contain null values
                    foreach (object o in valueList)
                    {
                        if (o == null)
                        {
                            throw new ArgumentException("Property '" + id + "' contains null values!");
                        }

                        propertyData.AddValue(o);
                    }
                }
                else
                {
                    if (definition.Cardinality != Cardinality.Single)
                    {
                        throw new ArgumentException("Property '" + id + "' is not a single value property!");
                    }

                    propertyData.AddValue(value);
                }

                result.AddProperty(propertyData);
            }

            return(result);
        }