protected override object GetInstance(string id) { if (string.IsNullOrEmpty(id)) { return(JsonEntity.CreateNew(_type)); } return(_entityContext.Fetch(_type, int.Parse(id))); }
public object Fetch(Type type, int id) { if (!supportedTypes.Contains(type)) { throw new NotSupportedException("Type '" + type.Name + "' is not supported."); } IJsonEntity entity; Dictionary <int, IJsonEntity> typeEntities; if (!_existingEntities.TryGetValue(type, out typeEntities)) { _existingEntities[type] = typeEntities = new Dictionary <int, IJsonEntity>(); } else if (typeEntities.TryGetValue(id, out entity)) { return(entity); } Dictionary <string, object> entityData; var typeData = GetTypeData(type); if (!typeData.TryGetValue(id.ToString(CultureInfo.InvariantCulture), out entityData)) { return(null); } entity = JsonEntity.CreateExisting(type, id, _defaultConstructors); typeEntities[id] = entity; if (autoInitializeEntities) { InitializeInstance(type, entity, entityData); } return(entity); }
public static void BeforeGet(TEntity entity, string property) { if (!entity.IsInitialized.HasValue) { entity.IsInitialized = false; if (entity.Id.HasValue) { JsonEntity.OnInitExisting(entity); } else { JsonEntity.OnInitNew(entity); } // Initialize reference list properties. foreach (var p in entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { Type listItemType; if (JsonEntity.TryGetListItemType(p.PropertyType, out listItemType)) { var list = p.GetValue(entity, null); if (list == null) { p.SetValue(entity, CreateList(listItemType), null); } } } entity.IsInitialized = true; } if (entity.IsInitialized.Value) { // Raise property get notifications ((IModelInstance)entity).Instance.OnPropertyGet(property); } }
public IEnumerable FetchAll(Type type) { if (!supportedTypes.Contains(type)) { throw new NotSupportedException("Type '" + type.Name + "' is not supported."); } Dictionary <int, IJsonEntity> typeEntities; if (!_existingEntities.TryGetValue(type, out typeEntities)) { typeEntities = new Dictionary <int, IJsonEntity>(); _existingEntities[type] = typeEntities; } var typeData = GetTypeData(type); lock (typeData) { foreach (var key in typeData.Keys) { var id = int.Parse(key); var entity = JsonEntity.CreateExisting(type, id, _defaultConstructors); typeEntities[id] = entity; if (autoInitializeEntities) { InitializeInstance(type, entity, typeData[key]); } } } return(typeEntities.Values); }
internal bool IsModified(IJsonEntity entity) { var type = entity.GetType(); var id = entity.Id; if (_deletedEntities.Contains(entity)) { if (!id.HasValue) { throw new Exception("Accessed deleted entity with no id: " + type.Name + "|."); } throw new Exception("Accessed deleted entity: " + type.Name + "|" + id + "."); } if (_pendingDeleteEntities.Contains(entity)) { return(true); } if (_newEntities.Contains(entity)) { return(true); } if (!id.HasValue) { throw new Exception("Found existing entity with no id: " + type.Name + "|."); } var typeData = GetTypeData(type); Dictionary <string, object> instanceData; if (typeData == null || !typeData.TryGetValue(id.Value.ToString(CultureInfo.InvariantCulture), out instanceData)) { throw new Exception("Couldn't find data for existing entity: " + type.Name + "|."); } foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (property.Name == "Id") { continue; } var value = property.GetValue(entity, null); var propertyType = property.PropertyType; object propertyData; var hasPropertyData = instanceData.TryGetValue(property.Name, out propertyData); Type referenceType; bool isReferenceList; if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList)) { if (isReferenceList) { var referenceIds = new List <int>(); foreach (IJsonEntity reference in (IEnumerable)value) { var referenceId = reference.Id; if (!referenceId.HasValue) { throw new InvalidOperationException(); } referenceIds.Add(referenceId.Value); } if (!hasPropertyData || IsReferenceListModified(referenceIds.ToArray(), propertyData)) { return(true); } } else { var referenceId = ((IJsonEntity)value).Id; if (!referenceId.HasValue) { throw new InvalidOperationException(); } if (!hasPropertyData || IsReferenceModified(referenceId, propertyData)) { return(true); } } } else if (!hasPropertyData || IsValueModified(value, propertyData)) { return(true); } } return(false); }
private void UpdateData(Type type, IJsonEntity entity, bool allowDelete, out Type[] affectedTypes, out object[] addedEntities, out object[] removedEntities) { var affected = new List <Type>(); var added = new List <object>(); var removed = new List <object>(); var typeData = GetTypeData(type, true); if (_deletedEntities.Contains(entity)) { var id = entity.Id; if (!id.HasValue) { throw new Exception("Found deleted entity with no id: " + type.Name + "|."); } throw new Exception("Found deleted entity: " + type.Name + "|" + id + "."); } if (_pendingDeleteEntities.Contains(entity)) { var id = entity.Id; if (!allowDelete) { throw new Exception("Cannot delete entity: " + type.Name + "|" + id + "."); } // Only need to delete Entities that were actually saved previously. if (id.HasValue) { if (typeData.ContainsKey(id.Value.ToString(CultureInfo.InvariantCulture))) { typeData.Remove(id.Value.ToString(CultureInfo.InvariantCulture)); } removed.Add(entity); affected.Add(type); if (!_deletedEntities.Contains(entity)) { _deletedEntities.Add(entity); } } _pendingDeleteEntities.Remove(entity); } else { var updated = false; Dictionary <string, object> instanceData; if (_newEntities.Contains(entity)) { int newId; if (typeData.Count == 0) { newId = 1; } else { var largestId = typeData.Keys.Max(k => int.Parse(k)); newId = largestId + 1; } entity.Id = newId; typeData[newId.ToString(CultureInfo.InvariantCulture)] = instanceData = new Dictionary <string, object>(); _newEntities.Remove(entity); added.Add(entity); Dictionary <int, IJsonEntity> instanceCache; if (!_existingEntities.TryGetValue(type, out instanceCache)) { _existingEntities[type] = instanceCache = new Dictionary <int, IJsonEntity>(); } instanceCache[newId] = entity; updated = true; } else { var id = entity.Id; if (!id.HasValue) { throw new Exception("Found existing entity with no id: " + type.Name + "|."); } if (!typeData.TryGetValue(id.Value.ToString(CultureInfo.InvariantCulture), out instanceData)) { throw new Exception("Couldn't find data for existing entity: " + type.Name + "|."); } } foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (property.Name == "Id") { continue; } var value = property.GetValue(entity, null); object serializedValue; var propertyType = property.PropertyType; object propertyData; var hasPropertyData = instanceData.TryGetValue(property.Name, out propertyData); Type referenceType; bool isReferenceList; if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList)) { if (isReferenceList) { var references = ((IEnumerable)value).Cast <IJsonEntity>().ToArray(); var referenceIds = new List <int>(); foreach (var reference in references) { Type[] refAffectedTypes; object[] refAdded; object[] refRemoved; UpdateData(referenceType, reference, false, out refAffectedTypes, out refAdded, out refRemoved); affected.AddRange(refAffectedTypes); added.AddRange(refAdded); removed.AddRange(refRemoved); var referenceId = reference.Id; if (!referenceId.HasValue) { throw new InvalidOperationException(); } referenceIds.Add(referenceId.Value); } serializedValue = referenceIds.ToArray(); if (!hasPropertyData) { updated = true; } else { if (IsReferenceListModified(referenceIds.ToArray(), propertyData)) { updated = true; } var persistedReferences = ((IEnumerable)propertyData).Cast <object>().Select(i => (int)Convert.ChangeType(i, typeof(int))).ToArray(); foreach (var priorReference in persistedReferences.Select(id => Fetch(referenceType, id)).Where(r => !references.Contains(r))) { Type[] refAffectedTypes; object[] refAdded; object[] refRemoved; UpdateData(referenceType, (IJsonEntity)priorReference, true, out refAffectedTypes, out refAdded, out refRemoved); affected.AddRange(refAffectedTypes); added.AddRange(refAdded); removed.AddRange(refRemoved); } } } else { int?referenceId; if (value == null) { referenceId = null; } else { Type[] refAffectedTypes; object[] refAdded; object[] refRemoved; UpdateData(referenceType, (IJsonEntity)value, false, out refAffectedTypes, out refAdded, out refRemoved); affected.AddRange(refAffectedTypes); added.AddRange(refAdded); removed.AddRange(refRemoved); referenceId = ((IJsonEntity)value).Id; if (!referenceId.HasValue) { throw new InvalidOperationException(); } } serializedValue = referenceId; if (!hasPropertyData) { updated = true; } else { if (IsReferenceModified(referenceId, propertyData)) { updated = true; } if (propertyData != null) { var priorReferenceId = (int?)propertyData; if (priorReferenceId != referenceId) { var priorReference = (IJsonEntity)Fetch(referenceType, priorReferenceId.Value); Type[] refAffectedTypes; object[] refAdded; object[] refRemoved; UpdateData(referenceType, priorReference, true, out refAffectedTypes, out refAdded, out refRemoved); affected.AddRange(refAffectedTypes); added.AddRange(refAdded); removed.AddRange(refRemoved); } } } } } else { serializedValue = value; if (!hasPropertyData || IsValueModified(value, propertyData)) { updated = true; } } instanceData[property.Name] = serializedValue; } if (updated) { affected.Add(type); } } affectedTypes = affected.ToArray(); addedEntities = added.ToArray(); removedEntities = removed.ToArray(); }
private void InitializeInstance(IReflect type, IJsonEntity entity, Dictionary <string, object> data) { var jsonProperties = data.Keys.ToArray(); foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var propertyType = property.PropertyType; Type referenceType; bool isReferenceList; object propData; if (jsonProperties.Contains(property.Name)) { propData = data[property.Name]; } else { propData = null; if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList)) { if (isReferenceList) { var list = JsonEntityAdapter <JsonEntity> .CreateList(referenceType); property.SetValue(entity, list, null); } } } if (propData == null) { continue; } object value; if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList)) { if (isReferenceList) { var list = JsonEntityAdapter <JsonEntity> .CreateList(referenceType); var addMethod = list.GetType().GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new[] { referenceType }, null); foreach (var referenceId in (IEnumerable)propData) { var reference = Fetch(referenceType, (int)Convert.ChangeType(referenceId, typeof(int))); if (reference == null) { throw new InvalidOperationException(); } addMethod.Invoke(list, new[] { reference }); } value = list; } else { var referenceId = (int)Convert.ChangeType(propData, typeof(int)); value = Fetch(referenceType, referenceId); } } else { Type targetType; if (!TryGetNullableType(propertyType, out targetType)) { targetType = propertyType; } if (targetType == typeof(DateTime) && propData is string) { value = DateTime.Parse((string)propData); } else if (propData.GetType() != targetType) { value = Convert.ChangeType(propData, targetType); } else { value = propData; } } property.SetValue(entity, value, null); } }