private void ProcessCollectionChange(NotifyCollectionChangedAction action, IEnumerable items, string path, string propertyName, IDbEntity parentEntity)
        {
            if (!_isCreatingHandlers && IsValid(parentEntity.GetType(), path, propertyName))
            {
                if (action == NotifyCollectionChangedAction.Add)
                {
                    ICollection <PropertyChange> changes = new List <PropertyChange>();
                    foreach (IDbEntity navigationEntity in items.Cast <IDbEntity>())
                    {
                        string         entityPath = DbEntityUtilities.GenerateCollectionItemPath(path + propertyName, navigationEntity.Guid);
                        PropertyChange change     = new PropertyChange(entityPath, string.Empty, navigationEntity.Guid, null, navigationEntity, true, navigationEntity.State);
                        if (_entity.IsTrackingChanges)
                        {
                            changes.Add(change);
                            MergeChanges(navigationEntity, entityPath, !_entity.IsTrackingChanges);
                        }
                        CreateHandlers(navigationEntity, entityPath);
                    }

                    if (_entity.IsTrackingChanges)
                    {
                        AddChanges(changes);
                    }
                    Validate(null, true);
                }
                else if (action == NotifyCollectionChangedAction.Remove)
                {
                    ICollection <PropertyChange> changes = new List <PropertyChange>();
                    string propertyPath = DbEntityUtilities.GeneratePropertyPath(path, propertyName);
                    foreach (IDbEntity removedEntity in items.Cast <IDbEntity>())
                    {
                        string         entityPath = DbEntityUtilities.GenerateCollectionItemPath(propertyPath, removedEntity.Guid);
                        PropertyChange change     = new PropertyChange(entityPath, string.Empty, removedEntity.Guid, removedEntity, null, true, removedEntity.State);
                        if (_entity.IsTrackingChanges)
                        {
                            changes.Add(change);
                        }
                        RemoveHandlers(removedEntity, entityPath);
                        Validate(change, true);
                    }

                    if (_entity.IsTrackingChanges)
                    {
                        AddChanges(changes);
                    }
                    changes.Clear();
                }
            }
        }
        private void EntityPropertyChanged(object sender, DbEntityPropertyChangedEventArgs e, string path)
        {
            IDbEntity      entity = sender as IDbEntity;
            PropertyChange change = null;

            // Save a reference to the property changed
            if (!_isCreatingHandlers && IsValid(sender.GetType(), path, e.PropertyName) && (!e.PropertyName.Equals("IsDeleted") || entity.State == EntityState.Persisted))
            {
                string       propertyPath         = path + e.PropertyName;
                PropertyInfo p                    = entity.GetType().GetProperty(e.PropertyName);
                bool         isEnumerable         = p.GetGetMethod().ReturnType.IsIEnumerable();
                bool         isDbEntityEnumerable = false;
                bool         isIDbEntity          = DbEntityUtilities.IsIDbEntity(p);
                if (isIDbEntity)
                {
                    propertyPath = propertyPath + ".";
                    if (e.Before != null)
                    {
                        RemoveHandlers(e.Before as IDbEntity, propertyPath);
                    }

                    if (e.After != null)
                    {
                        // Defer any changes tracking that might have been recorded on the navigation entity to the root entity
                        IDbEntity navigationEntity = e.After as IDbEntity;
                        if (_entity.IsTrackingChanges)
                        {
                            MergeChanges(navigationEntity, propertyPath, !_entity.IsTrackingChanges);
                        }
                        CreateHandlers(navigationEntity, propertyPath);
                    }
                }
                else if ((isEnumerable && p.GetGetMethod().ReturnType.GetGenericArguments().Count() > 0 && DbEntityUtilities.IsIDbEntity(p.GetGetMethod().ReturnType.GetGenericArguments()[0])))
                {
                    isDbEntityEnumerable = true;
                    if (e.Before != null)
                    {
                        RemoveCollectionHandlers(entity, e.Before as IEnumerable <IDbEntity>, path, propertyPath + ".", p);
                    }

                    if (e.After != null)
                    {
                        foreach (IDbEntity navigationEntity in e.After as IEnumerable <IDbEntity> )
                        {
                            if (navigationEntity != null)
                            {
                                string entityPath = DbEntityUtilities.GenerateCollectionItemPath(propertyPath, navigationEntity.Guid);
                                if (_entity.IsTrackingChanges)
                                {
                                    MergeChanges(navigationEntity, entityPath, !_entity.IsTrackingChanges);
                                }
                                CreateHandlers(navigationEntity, entityPath);
                            }
                        }
                    }
                }

                if (_entity.IsTrackingChanges)
                {
                    change = new PropertyChange(path, e.PropertyName, entity.Guid, e.Before, e.After, entity.State);
                    if (isDbEntityEnumerable)
                    {
                        change = new PropertyChange(path, e.PropertyName, entity.Guid, e.Before, e.After);
                    }

                    PurgeLast(p.GetGetMethod().ReturnType, change);
                    AddChange(change);
                    Validate(change, isIDbEntity);
                }

                //_logTo.DebugQueue(new EntityPropertyChangedLogEntry(SettingsModel.Current.User.id, entity.PrimaryKeys, entity.GetType(), propertyPath));
            }
        }