public static void UpdatePrimaryKeys(IDictionary <string, Tuple <string, object>[]> pathsAndKeys, IDbEntity entity)
 {
     foreach (KeyValuePair <string, Tuple <string, object>[]> pathAndKeys in pathsAndKeys)
     {
         IDbEntity entityToUpdate = DbEntityDataBinder.Eval(pathAndKeys.Key, entity).Entity;
         UpdatePrimaryKeys(pathAndKeys.Value, entityToUpdate);
     }
 }
        private static string SerializeAsObject(IDbEntity entity, IEnumerable <string> propertyPaths, ICollection <string> entityReferences)
        {
            string json = string.Empty;

            StringBuilder sb = new StringBuilder();

            using (StringWriter sw = new StringWriter(sb))
            {
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    // Reduce the string size as much as possible
                    writer.Formatting = Formatting.None;
                    ISet <string> oneHopPaths = new HashSet <string>(propertyPaths.Where(p => HopsCount(p) == 1 && !p.Contains("[")).ToList());
                    oneHopPaths.UnionWith(CreateMissingOneHopCollectionPaths(propertyPaths));
                    oneHopPaths.UnionWith(CreateMissingOneHopEntityPaths(propertyPaths));

                    SerializePrimaryKeys(entity, writer);

                    // Encode any non-zero, non-null primary keys
                    foreach (Tuple <string, object> key in entity.PrimaryKeys.Where(k => !_nullOrZero(k.Item2)).OrderBy(k => k.Item1))
                    {
                        oneHopPaths.Remove("." + key.Item1);
                    }

                    // Navigate flat property paths
                    ISet <string> processedPaths = new HashSet <string>();
                    string        propertyName   = string.Empty;
                    foreach (string path in oneHopPaths)
                    {
                        if (processedPaths.Add(path))
                        {
                            propertyName = path.Substring(1);
                            PropertyInfo property = entity.GetType().GetProperty(propertyName);
                            var          value    = property.GetValue(entity, null);
                            // Property : Value
                            if (!IsIDbEntity(property) && (value == null || !value.GetType().IsIEnumerable()))
                            {
                                // Not a relation and not a
                                writer.WritePropertyName(propertyName);
                                writer.WriteValue(value);
                            }
                            else
                            {
                                ICollection <string> relationalPropertyPaths = propertyPaths
                                                                               .Where(p => p.StartsWith(path))
                                                                               .ToList();

                                // Essentially, every time a new relation is created, it should be attached to its related entity before any changes are made to it (e.g. set virtual property or add to virtual collection).
                                if (IsIDbEntity(property))
                                {
                                    // It is a many-to-one relation
                                    relationalPropertyPaths = relationalPropertyPaths
                                                              .Where(p => HopsCount(p) > 1)
                                                              .ToList();

                                    ICollection <string> flattenedRelationalPropertyPaths = relationalPropertyPaths
                                                                                            .Select(p => p.Substring(path.Length))
                                                                                            .Where(p => !string.IsNullOrEmpty(p))
                                                                                            .ToList();

                                    IDbEntity relationalEntity = DbEntityDataBinder.Eval(path, entity).Entity;
                                    string    relationalJson   = "null";
                                    if (relationalEntity != null)
                                    {
                                        relationalJson = SerializeEntity(relationalEntity, flattenedRelationalPropertyPaths, entityReferences);
                                    }
                                    flattenedRelationalPropertyPaths.Clear();

                                    writer.WritePropertyName(propertyName);
                                    writer.WriteRawValue(relationalJson);
                                }
                                else
                                {
                                    // It is a collection relation (i.e. one-to-many or many-to-many)
                                    writer.WritePropertyName(propertyName);
                                    writer.WriteStartArray();
                                    List <string> collectionEntityPaths = relationalPropertyPaths
                                                                          .Where(p => HopsCount(p) > 1)
                                                                          .Select(p => p.Substring(0, p.IndexOf('.', 1)))
                                                                          .Distinct()
                                                                          .ToList();
                                    collectionEntityPaths.AddRange(relationalPropertyPaths.Where(p => HopsCount(p) == 1));
                                    foreach (string collectionEntityPath in collectionEntityPaths.Distinct())
                                    {
                                        IDbEntity            collectionEntity = DbEntityDataBinder.Eval(collectionEntityPath, entity).Entity;
                                        ICollection <string> flattenedCollectionEntityPaths = relationalPropertyPaths
                                                                                              .Where(p => p.StartsWith(collectionEntityPath))
                                                                                              .Select(p => p.Substring(collectionEntityPath.Length))
                                                                                              .ToList();

                                        string collectionEntityJson = SerializeEntity(collectionEntity, flattenedCollectionEntityPaths, entityReferences);
                                        writer.WriteRawValue(collectionEntityJson);
                                        flattenedCollectionEntityPaths.Clear();
                                    }

                                    writer.WriteEndArray();
                                    collectionEntityPaths.Clear();
                                }

                                processedPaths.UnionWith(relationalPropertyPaths);
                                relationalPropertyPaths.Clear();
                            }
                        }
                    }

                    oneHopPaths.Clear();

                    // End object
                    writer.WriteEndObject();
                }

                sw.Flush();
                json = sw.ToString();
                sb.Clear();
            }

            return(json);
        }
        private static string ConvertPath(IDbEntity entity, string pathPrefix, string collectionItemPath)
        {
            IDbEntity collectionItem = DbEntityDataBinder.Eval(pathPrefix + collectionItemPath, entity).Entity;

            return(GenerateCollectionItemPath(collectionItemPath.Substring(0, collectionItemPath.IndexOf("[")), collectionItem.PrimaryKeys, collectionItem.Guid));
        }