private void PopulateNavigateResult(EntitySetDataRow row, QueryEntityValue entityInstance, AssociationSet associationSet, AssociationSetEnd fromSetEnd, AssociationSetEnd toSetEnd) { EntityContainerData containerData = row.Parent.Parent; var associationSetData = containerData.GetAssociationSetData(associationSet.Name); var targetInstanceLookup = this.rowInstances[toSetEnd.EntitySet.Name]; var associatedObjects = associationSetData.Rows .Where(r => r.GetRoleKey(fromSetEnd.AssociationEnd.RoleName).Equals(row.Key)) .Select(r => targetInstanceLookup[r.GetRoleKey(toSetEnd.AssociationEnd.RoleName)]) .ToArray(); var toEntityType = toSetEnd.AssociationEnd.EntityType; var toQueryEntityType = this.GetQueryType(toSetEnd.EntitySet.Name, toEntityType); if (toSetEnd.AssociationEnd.Multiplicity == EndMultiplicity.Many) { var collectionType = toQueryEntityType.CreateCollectionType(); var collectionValue = collectionType.CreateCollectionWithValues(associatedObjects); entityInstance.SetNavigateResult(associationSet.AssociationType, toSetEnd.AssociationEnd, collectionValue); } else { if (associatedObjects.Length == 0) { entityInstance.SetNavigateResult(associationSet.AssociationType, toSetEnd.AssociationEnd, toQueryEntityType.NullValue); } else { if (associatedObjects.Length != 1) { var debugAssociatedValues = string.Join("," + Environment.NewLine, associatedObjects.Select(ao => ao.ToString())); throw new TaupoInfrastructureException( string.Format( CultureInfo.InvariantCulture, "Found {0} associated objects for {1}.{2}, on Entity Instance {3} associated Objects = {4}", associatedObjects.Length, associationSet.AssociationType.FullName, fromSetEnd.AssociationEnd.RoleName, entityInstance, debugAssociatedValues)); } var targetInstance = associatedObjects.Single(); entityInstance.SetNavigateResult(associationSet.AssociationType, toSetEnd.AssociationEnd, targetInstance); } } }
/// <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); } } }