Inheritance: IJsonEntity
Example #1
0
            protected override object GetInstance(string id)
            {
                if (string.IsNullOrEmpty(id))
                {
                    return(JsonEntity.CreateNew(_type));
                }

                return(_entityContext.Fetch(_type, int.Parse(id)));
            }
Example #2
0
        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);
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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();
        }
Example #7
0
        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);
            }
        }