protected override void UpdateRelatedEndInternal(
            CustomObjectContext objectContext,
            RelatedEndEntityObject relatedEntityObject,
            CustomStoreOperationKind changeKind
            )
        {
            if (CustomStoreOperationKind.Add == changeKind)
            {
                if (null != RelationshipMetadata.To.RelatedProperty)
                {
                    RelationshipMetadata.To.RelatedProperty.SetValue(relatedEntityObject, _thisEndObject);
                }

                if (null != objectContext)
                {
                    objectContext.AddObject(RelationshipMetadata.To.EntitySetType.Name, relatedEntityObject);
                }
            }
            else
            {
                Debug.Assert(CustomStoreOperationKind.Delete == changeKind);

                if (null != RelationshipMetadata.To.RelatedProperty)
                {
                    RelationshipMetadata.To.RelatedProperty.SetValue(relatedEntityObject, null);
                }

                if (null != objectContext)
                {
                    objectContext.DeleteObject(relatedEntityObject);
                }
            }
        }
        public override void CascadeStoreOperation(CustomStoreOperationKind changeKind)
        {
            CustomObjectContext context = ObjectContextWeakRef.Target;

            Debug.Assert(null != context);

            Queue <object> objectsToBeRemoved = null;

            foreach (object entityObject in this)
            {
                if (CustomStoreOperationKind.Add == changeKind)
                {
                    context.AddObject(RelationshipMetadata.To.EntitySetType.Name, entityObject);
                }
                else if (CustomStoreOperationKind.Delete == changeKind)
                {
                    if (null == objectsToBeRemoved)
                    {
                        objectsToBeRemoved = new Queue <object>();
                    }
                    objectsToBeRemoved.Enqueue(entityObject);
                }
            }

            if (null != objectsToBeRemoved && objectsToBeRemoved.Count > 0)
            {
                foreach (object entityObject in objectsToBeRemoved)
                {
                    Remove(entityObject);
                    DeleteObjectIfTransietOrphan(context, entityObject);
                }
            }
        }
 protected virtual void ValidateStateTransitionInternal(
     CustomObjectContext objectContext,
     EntityObjectType relatedEntityObject,
     CustomStoreOperationKind changeKind
     )
 {
 }
        protected override void OnChangeCompleted(
            object relatedEntityObject,
            CustomStoreOperationKind changeKind
            )
        {
            base.OnChangeCompleted(relatedEntityObject, changeKind);

            if (null != ObjectContextWeakRef)
            {
                Debug.Assert(relatedEntityObject is EntityObjectType);

                CustomObjectContext objectContext = ObjectContextWeakRef.Target;
                if (null != objectContext && null != RelationshipMetadata)
                {
                    var thisRelationshipEnd = new CustomRelationshipEnd(_thisEndEntityObject, RelationshipMetadata.From);
                    if (objectContext.RelationshipHelper.IsVisitedRelationshipEnd(thisRelationshipEnd))
                    {
                        return;
                    }

                    try
                    {
                        objectContext.RelationshipHelper.AddToVisitedRelationshipEnds(thisRelationshipEnd);
                        UpdateRelatedEndInternal(objectContext, (EntityObjectType)relatedEntityObject, changeKind);
                    }
                    finally
                    {
                        objectContext.RelationshipHelper.RemoveFromVisitedRelationshipEnds(thisRelationshipEnd);
                    }
                }
            }
        }
        protected void ValidateStateTransition(
            EntityObjectType relatedEntityObject,
            CustomStoreOperationKind changeKind
            )
        {
            if (null != ObjectContextWeakRef)
            {
                CustomObjectContext objectContext = ObjectContextWeakRef.Target;
                if (null != objectContext && null != RelationshipMetadata)
                {
                    var thisRelationshipEnd = new CustomRelationshipEnd(_thisEndEntityObject, RelationshipMetadata.From);
                    if (objectContext.RelationshipHelper.IsVisitedRelationshipEnd(thisRelationshipEnd))
                    {
                        return;
                    }

                    try
                    {
                        objectContext.RelationshipHelper.AddToVisitedRelationshipEnds(thisRelationshipEnd);
                        ValidateStateTransitionInternal(objectContext, relatedEntityObject, changeKind);
                    }
                    finally
                    {
                        objectContext.RelationshipHelper.RemoveFromVisitedRelationshipEnds(thisRelationshipEnd);
                    }
                }
            }
        }
 protected virtual void OnChangeCompleted(object entityObject, CustomStoreOperationKind changeKind)
 {
     if (CustomStoreOperationKind.Add == changeKind)
     {
         CustomCollectionChangeKind oldChangeKind;
         if (ChangeEntries.TryGetValue(entityObject, out oldChangeKind))
         {
             Debug.Assert(oldChangeKind == CustomCollectionChangeKind.Deleted);
             bool removed = ChangeEntries.Remove(entityObject);
             Debug.Assert(removed);
         }
         else
         {
             ChangeEntries[entityObject] = CustomCollectionChangeKind.Added;
         }
     }
     else if (CustomStoreOperationKind.Delete == changeKind)
     {
         CustomCollectionChangeKind oldChangeKind;
         if (ChangeEntries.TryGetValue(entityObject, out oldChangeKind))
         {
             Debug.Assert(oldChangeKind == CustomCollectionChangeKind.Added);
             bool removed = ChangeEntries.Remove(entityObject);
             Debug.Assert(removed);
         }
         else
         {
             ChangeEntries[entityObject] = CustomCollectionChangeKind.Deleted;
         }
     }
     else
     {
         Debug.Fail("Unexpected change kind", changeKind.ToString());
     }
 }
        protected override void UpdateRelatedEndInternal(
            CustomObjectContext objectContext,
            RelatedEndEntityObject relatedEntityObject,
            CustomStoreOperationKind changeKind
            )
        {
            if (CustomStoreOperationKind.Add == changeKind)
            {
                if (null != RelationshipMetadata.To.RelatedProperty)
                {
                    object relatedManyToManyCollection = RelationshipMetadata.To.RelatedProperty.GetValue(relatedEntityObject);
                    Debug.Assert(null != relatedManyToManyCollection);

                    if (relatedManyToManyCollection is CustomObjectCollectionBase)
                    {
                        Debug.Assert(relatedManyToManyCollection is CustomObjectCollectionBase);
                        var managedManyToManyCollection = (CustomObjectCollectionBase)relatedManyToManyCollection;
                        managedManyToManyCollection.Add(_thisEndObject);
                    }
                    else
                    {
                        MethodInfo addMethod = relatedManyToManyCollection.GetType().GetMethod("Add");
                        Debug.Assert(null != addMethod);
                        addMethod.Invoke(relatedManyToManyCollection, new object[] { _thisEndObject });
                    }
                }

                if (null != objectContext)
                {
                    objectContext.AddObject(RelationshipMetadata.To.EntitySetType.Name, relatedEntityObject);
                }
            }
            else
            {
                Debug.Assert(CustomStoreOperationKind.Delete == changeKind);

                if (null != RelationshipMetadata.To.RelatedProperty)
                {
                    object relatedManyToManyCollection = RelationshipMetadata.To.RelatedProperty.GetValue(relatedEntityObject);
                    if (relatedManyToManyCollection is CustomObjectCollectionBase)
                    {
                        Debug.Assert(relatedManyToManyCollection is CustomObjectCollectionBase);
                        var managedManyToManyCollection = (CustomObjectCollectionBase)relatedManyToManyCollection;
                        managedManyToManyCollection.Remove(_thisEndObject);
                    }
                    else
                    {
                        MethodInfo removeMethod = relatedManyToManyCollection.GetType().GetMethod("Remove");
                        Debug.Assert(null != removeMethod);
                        removeMethod.Invoke(relatedManyToManyCollection, new object[] { _thisEndObject });
                    }

                    if (null != objectContext)
                    {
                        DeleteObjectIfTransietOrphan(objectContext, relatedEntityObject);
                    }
                }
            }
        }
        public override void CascadeStoreOperation(CustomStoreOperationKind operationKind)
        {
            CustomObjectContext context = ObjectContextWeakRef.Target;

            Debug.Assert(null != context);

            foreach (object entityObject in this)
            {
                if (CustomStoreOperationKind.Add == operationKind)
                {
                    context.AddObject(RelationshipMetadata.To.EntitySetType.Name, entityObject);
                }
                else if (CustomStoreOperationKind.Delete == operationKind)
                {
                    context.DeleteObject(entityObject);
                }
                else
                {
                    Debug.Fail("Unexpected store operation kind", operationKind.ToString());
                }
            }
        }
        protected override void ValidateStateTransitionInternal(
            CustomObjectContext objectContext,
            RelatedEndEntityObject relatedEntityObject,
            CustomStoreOperationKind changeKind
            )
        {
            if (Object.ReferenceEquals(_thisEndObject, relatedEntityObject))
            {
                throw new InvalidOperationException(String.Format(
                                                        "Cannot add entity object '{0}' to its one one-to-many collection.",
                                                        _thisEndObject
                                                        ));
            }

            if (CustomStoreOperationKind.Add == changeKind)
            {
                if (null != RelationshipMetadata.To.RelatedProperty)
                {
                    var sameOneEndRoleObject = RelationshipMetadata.To.RelatedProperty.GetValue(relatedEntityObject);
                    if (
                        !Object.ReferenceEquals(sameOneEndRoleObject, null) &&
                        !Object.ReferenceEquals(sameOneEndRoleObject, _thisEndObject))
                    {
#if _DO_NOT_REMOVE_SILENTLY_SAME_ROLE_INSTANCE
                        throw new InvalidOperationException(String.Format(
                                                                "Entity object '{0}' is already associated with another " +
                                                                "instance '{1}' of principal end in the one-to-many relationship " +
                                                                "between '{2}' and '{3}'.",
                                                                relatedEntityObject, sameOneEndRoleObject,
                                                                typeof(ThisEndEntityObject), typeof(RelatedEndEntityObject)
                                                                ));
#else
                        CustomEntityType entityType = RelationshipMetadata.From.EntityType;

                        // TODO: do we need this assert? saw it failing in Astoria tests; may be it is
                        // caused by multiple object contexts loaded from the same data source?
                        // in this implementation all object contexts share same objects
#if _NOT_ASTORIA_TESTS
                        Debug.Assert(entityType.ClrObjectType.IsAssignableFrom(sameOneEndRoleObject.GetType()));
#endif


                        object otherCollection = RelationshipMetadata.GetValue(sameOneEndRoleObject);
                        Debug.Assert(null != otherCollection);

                        if (otherCollection is CustomObjectCollectionBase)
                        {
                            bool removed = ((CustomObjectCollectionBase)otherCollection).Remove(relatedEntityObject);

                            // TODO: need to investigate; saw a failure here with Northwind model in Astoria tests
                            // same problem with many object contexts loaded from the same data source as above?
#if _NOT_ASTORIA_TESTS
                            Debug.Assert(removed);
#endif
                        }
                        else
                        {
                            MethodInfo removeMethod = otherCollection.GetType().GetMethod("Remove");
                            Debug.Assert(null != removeMethod);
                            removeMethod.Invoke(otherCollection, new object[] { relatedEntityObject });
                        }
#endif
                    }
                }
            }
        }
 protected abstract void UpdateRelatedEndInternal(
     CustomObjectContext objectContext,
     EntityObjectType relatedEntityObject,
     CustomStoreOperationKind changeKind
     );
 public abstract void CascadeStoreOperation(CustomStoreOperationKind changeKind);