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)); }