private static void InvokeConnectEntitiesCallback(
     IEntitySetData source,
     IEntitySetData target,
     RelationshipType relationship,
     RelationshipSide sourceSide,
     HashSet <AssociationInstance> processedAssociations,
     ConnectEntitiesCallback connectEntities)
 {
     if (connectEntities != null && processedAssociations.Add(new AssociationInstance(source, target, relationship.AssociationType.Name, sourceSide.FromRoleName)))
     {
         connectEntities(source, target, relationship.AssociationType.Name, sourceSide.FromRoleName);
     }
 }
        /// <summary>
        /// Creates a set of objects based on the specified <paramref name="root"/> entity instance
        /// and only its required relationships.
        /// </summary>
        /// <param name="entitySetName">The entity set name for the root entity.</param>
        /// <param name="root">The root entity around which the graph is based.</param>
        /// <param name="entityCreated">A callback function invoked every time a new entity instance is created and its properties are initialized.</param>
        /// <param name="connectEntities">A callback used to connect two objects together. Examples of actions include setting navigation properties,
        /// synchronizing FKs to PK values, and/or using the IRelatedEnd or SetLink APIs. The first two parameters are the objects that need to
        /// be connected, and the third is the <see cref="RelationshipSide"/> describing the side of the relationship which the first object participates
        /// in.</param>
        /// <returns>A list of <see cref="IEntitySetData"/> representing all objects in the graph used to satisfy the required relationships.
        /// The first object in the list is always the <paramref name="root"/>.</returns>
        public IList <IEntitySetData> CreateGraphWithRequiredRelationships(
            string entitySetName,
            object root,
            Action <IEntitySetData> entityCreated,
            ConnectEntitiesCallback connectEntities)
        {
            ExceptionUtilities.CheckArgumentNotNull(root, "root");
            ExceptionUtilities.CheckStringArgumentIsNotNullOrEmpty(entitySetName, "entitySetName");

            ExceptionUtilities.CheckObjectNotNull(
                this.ObjectServices,
                "An {0} instance is required to create graphs. Populate the ObjectServices property.",
                typeof(IEntityModelObjectServices).Name,
                ExpressionUtilities.NameOf(() => this.ObjectServices));

            var dataPopulationDriver = this.CreateDataPopulationDriver();

            var rootEntitySet  = this.entityContainer.EntitySets.SingleOrDefault(es => es.ContainerQualifiedName == entitySetName);
            var rootEntityType = this.entityContainer.Model.EntityTypes.SingleOrDefault(et => et.Name == root.GetType().Name);

            ExceptionUtilities.CheckObjectNotNull(rootEntitySet, "Could not locate entity set '{0}' in the model.", entitySetName);
            ExceptionUtilities.CheckObjectNotNull(rootEntityType, "Could not locate entity type '{0}' in the model.", root.GetType().FullName);

            var rootKey = dataPopulationDriver.Seed(rootEntitySet, rootEntityType, this.ObjectServices.GetPropertiesValues(root, rootEntityType));

            var data     = this.CreateEntityContainerData(dataPopulationDriver);
            var graph    = new List <IEntitySetData>();
            var rootData = this.CreateEntitySetObjectData(root, entitySetName);

            graph.Add(rootData);

            if (data != null)
            {
                var processedEntities = new Dictionary <EntityKey, IEntitySetData>();
                processedEntities.Add(new EntityKey(entitySetName, rootKey), rootData);
                this.CreateGraphCore(
                    graph,
                    rootData,
                    rootEntitySet,
                    rootEntityType,
                    rootKey,
                    data,
                    processedEntities,
                    new HashSet <AssociationInstance>(),
                    entityCreated,
                    connectEntities);
            }

            return(graph);
        }
        /// <summary>
        /// Examines the required relationships from <paramref name="source"/> and then populates them in <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The <see cref="List{IEntitySetData}"/> to which to add the new instance.</param>
        /// <param name="source">The entity from which to find required relationships and populate them.</param>
        /// <param name="sourceEntitySet">The <see cref="EntitySet"/> in which <paramref name="source"/> resides.</param>
        /// <param name="sourceEntityType">The <see cref="EntityType"/> of which the <paramref name="source"/> is an instance.</param>
        /// <param name="sourceKey">The <see cref="EntityDataKey"/> of the <paramref name="source"/> instance.</param>
        /// <param name="data"><see cref="EntityContainerData"/> that contains the structural data from which to create objects.</param>
        /// <param name="processedEntities">The entity instances which have been translated from structural data into objects.</param>
        /// <param name="processedAssociations">The association instances which have been translated from structural data into calls to <paramref name="connectEntities"/>.</param>
        /// <param name="entityCreated">A callback function invoked every time a new entity instance is created and its properties are initialized.</param>
        /// <param name="connectEntities">A callback used to connect two objects together. Examples of actions include setting navigation properties,
        /// synchronizing FKs to PK values, and/or using the IRelatedEnd or SetLink APIs. The first two parameters are the objects that need to
        /// be connected, and the third is the <see cref="RelationshipSide"/> describing the side of the relationship which the first object participates
        /// in.</param>
        private void CreateGraphCore(
            List <IEntitySetData> graph,
            IEntitySetData source,
            EntitySet sourceEntitySet,
            EntityType sourceEntityType,
            EntityDataKey sourceKey,
            EntityContainerData data,
            Dictionary <EntityKey, IEntitySetData> processedEntities,
            HashSet <AssociationInstance> processedAssociations,
            Action <IEntitySetData> entityCreated,
            ConnectEntitiesCallback connectEntities)
        {
            var requiredRelationships =
                from r in sourceEntitySet.Container.RelationshipTypes()
                let side = r.Sides.FirstOrDefault(e =>
                                                  sourceEntityType.IsKindOf(e.FromEntityType) &&
                                                  sourceEntitySet == e.FromEntitySet &&
                                                  e.ToMultiplicity == EndMultiplicity.One)
                           where side != null
                           select new
            {
                Relationship = r,
                SourceSide   = side
            };

            foreach (var r in requiredRelationships)
            {
                var relationship   = r.Relationship;
                var sourceSide     = r.SourceSide;
                var associationRow = data.GetAssociationSetData(relationship.AssociationSet.Name).Rows
                                     .Single(row => row.GetRoleKey(sourceSide.FromRoleName).Equals(sourceKey));
                var targetKey       = associationRow.GetRoleKey(sourceSide.ToRoleName);
                var targetEntitySet = sourceSide.ToEntitySet;
                var targetEntityKey = new EntityKey(targetEntitySet.ContainerQualifiedName, targetKey);

                IEntitySetData targetEntity;
                if (!processedEntities.TryGetValue(targetEntityKey, out targetEntity))
                {
                    var targetRow = data.GetEntitySetData(targetEntitySet.Name).Rows.Single(row => row.Key.Equals(targetKey));
                    targetEntity = this.CreateObjectFromRow(targetRow);

                    if (entityCreated != null)
                    {
                        entityCreated(targetEntity);
                    }

                    graph.Add(targetEntity);
                    processedEntities.Add(targetEntityKey, targetEntity);
                    InvokeConnectEntitiesCallback(source, targetEntity, relationship, sourceSide, processedAssociations, connectEntities);

                    this.CreateGraphCore(
                        graph,
                        targetEntity,
                        targetEntitySet,
                        targetRow.EntityType,
                        targetKey,
                        data,
                        processedEntities,
                        processedAssociations,
                        entityCreated,
                        connectEntities);
                }
                else
                {
                    InvokeConnectEntitiesCallback(source, targetEntity, relationship, sourceSide, processedAssociations, connectEntities);
                }
            }
        }