private Address AttachWithRelations(Address entity, InsertMode insertMode = InsertMode.Attach, MergeOption mergeOption = MergeOption.AppendOnly, List <object> referenceTrackingList = null)
        {
            #region iteration tracking

            if (ReferenceEquals(null, referenceTrackingList))
            {
                referenceTrackingList = new List <object>();
            }

            if (referenceTrackingList.Contains(entity))
            {
                return(_addresses.GetExisting(entity));
            }
            else
            {
                referenceTrackingList.Add(entity);
            }

            #endregion

            #region add/attach entity

            Address existingEntity = null;

            switch (insertMode)
            {
            case InsertMode.Add:
                existingEntity = _addresses.Add(entity);
                break;

            case InsertMode.Attach:
                existingEntity = _addresses.Attach(entity);
                break;

            default:
                throw new Exception(string.Format("Implementation Exception: missing action for {0}", insertMode));
            }

            if (!ReferenceEquals(null, existingEntity) && ReferenceEquals(existingEntity, entity))
            {
                return(existingEntity);
            }

            #endregion

            #region attach relations recursively


            if (!ReferenceEquals(null, entity.Customers))
            {
                // register relation's collection changed event if entity is new to context
                if (ReferenceEquals(null, existingEntity))
                {
                    entity.Customers.CollectionChanged += On_address_customers_collectionChanged;
                }

                // attach related entities to context
                if (entity.Customers.Count > 0)
                {
                    foreach (var item in entity.Customers.ToArray())
                    {
                        var existingRelatedEntity = (Customer)AttachWithRelations(item, insertMode, mergeOption, referenceTrackingList);

                        // update relation if entity is new to context or relation is new to entity
                        if (ReferenceEquals(null, existingEntity) || !existingEntity.Customers.Contains(item))
                        {
                            if (!ReferenceEquals(null, existingRelatedEntity) && !ReferenceEquals(existingRelatedEntity, item))
                            {
                                // check merge options
                                if (!(mergeOption == MergeOption.PreserveChanges && existingRelatedEntity.ChangeTracker.OriginalValues.ContainsKey("Address")))
                                {
                                    using (entity.ChangeTrackingPrevention())
                                    {
                                        entity.Customers.Replace(item, existingRelatedEntity);
                                    }

                                    using (existingRelatedEntity.ChangeTrackingPrevention())
                                    {
                                        existingRelatedEntity.Address = entity;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (!ReferenceEquals(null, entity.People))
            {
                // register relation's collection changed event if entity is new to context
                if (ReferenceEquals(null, existingEntity))
                {
                    entity.People.CollectionChanged += On_address_people_collectionChanged;
                }

                // attach related entities to context
                if (entity.People.Count > 0)
                {
                    foreach (var item in entity.People.ToArray())
                    {
                        var existingRelatedEntity = AttachWithRelations(item, insertMode, mergeOption, referenceTrackingList);

                        // update relation if entity is new to context or relation is new to entity
                        if (ReferenceEquals(null, existingEntity) || !existingEntity.People.Contains(item))
                        {
                            if (!ReferenceEquals(null, existingRelatedEntity) && !ReferenceEquals(existingRelatedEntity, item))
                            {
                                // check merge options
                                if (!(mergeOption == MergeOption.PreserveChanges && existingRelatedEntity.ChangeTracker.OriginalValues.ContainsKey("Address1")))
                                {
                                    using (entity.ChangeTrackingPrevention())
                                    {
                                        entity.People.Replace(item, existingRelatedEntity);
                                    }

                                    using (existingRelatedEntity.ChangeTrackingPrevention())
                                    {
                                        existingRelatedEntity.Address1 = entity;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            #endregion

            #region refresh existing entity based on merge options

            if (!ReferenceEquals(null, existingEntity) && !ReferenceEquals(existingEntity, entity))
            {
                if (Addresses.MergeOption == MergeOption.OverwriteChanges)
                {
                    Invoke(delegate
                    {
                        existingEntity.Refresh(entity, trackChanges: false);
                        existingEntity.AcceptChanges();
                    });
                }
                else if (Addresses.MergeOption == MergeOption.PreserveChanges)
                {
                    Invoke(delegate
                    {
                        existingEntity.Refresh(entity, trackChanges: false, preserveExistingChanges: true);
                    });
                }
            }

            #endregion

            return(existingEntity);
        }