private void AddValueLevel( object obj, Type parentType, string parentId) { if (obj == null) { return; } Type type = obj.GetType(); string typeName = type.Name; var idPropertyName = _typeInfo.GetIdPropertyName(typeName); var typeData = _typeInfo.PropertiesMap[type]; string id = null; if (typeData.ValueProperties.Count > 0) { StringBuilder sb = new StringBuilder(); bool hasParentIdProperty = false; for (int i = 0; i < typeData.ValueProperties.Count; ++i) { var valueProperty = typeData.ValueProperties[i]; object value = valueProperty.GetValue(obj); if (valueProperty.Name == _typeInfo.IdPropertyName || valueProperty.Name == idPropertyName) { if (value == null) { _log.WriteWarning(nameof(AddValueLevel), obj, $"Id property {valueProperty.Name} of {typeName} is null"); } id = value?.ToString() ?? string.Empty; } else { string strValue = string.Empty; if (value != null) { if (valueProperty.PropertyType == typeof(DateTime)) { strValue = DateTimeConverter.Convert((DateTime)value); } else if (valueProperty.PropertyType == typeof(DateTime?)) { strValue = DateTimeConverter.Convert(((DateTime?)value).Value); } else if (StructureBuilder.GenericCollectionTypes.Any(t => t == valueProperty.PropertyType)) { var strValues = new List <string>(); var enumerable = (IEnumerable)value; foreach (var item in enumerable) { strValues.Add(item.ToString() ?? string.Empty); } strValue = string.Join(';', strValues); } else { strValue = value.ToString(); } } if (typeData.ParentIdPropertyName != null && valueProperty.Name == typeData.ParentIdPropertyName) { hasParentIdProperty = true; } if (sb.Length > 0 || i > 0 && (i != 1 || id == null)) { sb.Append(','); } sb.Append(strValue); } } if (parentId != null && !hasParentIdProperty) { sb.Insert(0, $"{parentId},"); } else if (sb.Length > 0 && parentType != null && _typeInfo.PropertiesMap[parentType].ValueProperties.Count > 0) { _log.WriteWarning( nameof(AddValueLevel), obj, $"Message of type {parentType.Name} doesn't have any identificators that can be used to make relations to its children"); sb.Insert(0, ","); } if (id != null) { sb.Insert(0, $"{id},"); } if (_objectsData.ContainsKey(typeName)) { _objectsData[typeName].Add(sb.ToString()); } else { _objectsData.Add(typeName, new List <string> { sb.ToString() }); } } if (typeData.OneChildrenProperties.Count == 0 && typeData.ManyChildrenProperties.Count == 0) { return; } if (id == null) { id = GetIdFromChildren(obj, typeData); } if (id == null) { id = parentId; } if (id == null && typeData.RelationProperty != null) { id = typeData.RelationProperty.GetValue(obj)?.ToString(); } foreach (var childProperty in typeData.OneChildrenProperties) { object value = childProperty.GetValue(obj); if (value == null) { continue; } ProcessTypeItem( value, type, childProperty == typeData.ChildWithIdProperty ? null : id); } foreach (var childrenProperty in typeData.ManyChildrenProperties) { object value = childrenProperty.GetValue(obj); if (value == null) { continue; } var items = value as IEnumerable; if (items == null) { throw new InvalidOperationException($"Couldn't cast value '{value}' of property {childrenProperty.Name} from {typeName} to IEnumerable"); } foreach (var item in items) { ProcessTypeItem( item, type, childrenProperty == typeData.ChildWithIdProperty ? null : id); } } }