/// <summary> /// Builds relationship metadata /// </summary> /// <param name="serviceContext">Service Context</param> /// <param name="linkDetails">Link Details</param> /// <returns>Relationshi pMetadata</returns> private ProductAccessProvider.RelationshipMetadata BuildRelationshipMetadata(OrganizationServiceContext serviceContext, LinkDetails linkDetails) { // This is used for Mocking if (this.relationshipMetadataDictionary != null && this.relationshipMetadataDictionary.ContainsKey(linkDetails.Entity2Name)) { return(this.relationshipMetadataDictionary[linkDetails.Entity2Name]); } // Standard flow var entity1Metadata = GetEntityMetadata(serviceContext, linkDetails.Entity1Name); var entity2Metadata = linkDetails.Entity2Name == linkDetails.Entity1Name ? entity1Metadata : GetEntityMetadata(serviceContext, linkDetails.Entity2Name); var relationshipMetadata = new ProductAccessProvider.RelationshipMetadata(); relationshipMetadata.Entity1PrimaryIdAttribute = entity1Metadata.PrimaryIdAttribute; relationshipMetadata.Entity2PrimaryIdAttribute = entity2Metadata.PrimaryIdAttribute; relationshipMetadata.Entity1LogicalName = entity1Metadata.LogicalName; relationshipMetadata.Entity2LogicalName = entity2Metadata.LogicalName; var relationshipManyToMany = entity1Metadata.ManyToManyRelationships.FirstOrDefault(r => r.SchemaName == linkDetails.RelationshipName); if (relationshipManyToMany != null) { relationshipMetadata.RelationshipType = ProductAccessProvider.RelationshipType.ManyToManyRelationship; relationshipMetadata.Entity1LogicalName = relationshipManyToMany.Entity2LogicalName; relationshipMetadata.Entity2LogicalName = relationshipManyToMany.Entity1LogicalName; relationshipMetadata.Entity1IntersectAttribute = relationshipManyToMany.Entity2IntersectAttribute; relationshipMetadata.Entity2IntersectAttribute = relationshipManyToMany.Entity1IntersectAttribute; relationshipMetadata.IntersectEntityName = relationshipManyToMany.IntersectEntityName; return(relationshipMetadata); } var relationshipManyToOne = entity1Metadata.ManyToOneRelationships.FirstOrDefault(r => r.SchemaName == linkDetails.RelationshipName); if (relationshipManyToOne != null) { relationshipMetadata.RelationshipType = ProductAccessProvider.RelationshipType.ManyToOneRelationship; relationshipMetadata.ReferencedEntity = relationshipManyToOne.ReferencedEntity; relationshipMetadata.ReferencingAttribute = relationshipManyToOne.ReferencingAttribute; relationshipMetadata.ReferencedAttribute = relationshipManyToOne.ReferencedAttribute; return(relationshipMetadata); } var relationshipOneToMany = entity1Metadata.OneToManyRelationships.FirstOrDefault(r => r.SchemaName == linkDetails.RelationshipName); if (relationshipOneToMany != null) { relationshipMetadata.RelationshipType = ProductAccessProvider.RelationshipType.OneToManyRelationship; relationshipMetadata.ReferencedEntity = relationshipOneToMany.ReferencedEntity; relationshipMetadata.ReferencedAttribute = relationshipOneToMany.ReferencedAttribute; relationshipMetadata.ReferencingAttribute = relationshipOneToMany.ReferencingAttribute; return(relationshipMetadata); } // This would be a failed case return(null); }
/// <summary> /// Modify a fetch and add necessary link entity elements and filter conditions to satisfy record level security trimming based on the relationship definitions. /// </summary> /// <param name="serviceContext"><see cref="OrganizationServiceContext"/> to use</param> /// <param name="relationshipMetadata">Relationship metadata that defines relationship attributes</param> /// <param name="linkDetails"><see cref="ContentAccessProvider.LinkDetails"/> to use</param> /// <param name="fetch">Fetch to modify</param> /// <param name="link">Link to construct</param> /// <param name="filter">Filter to construct</param> /// <param name="contact">Associated Contact</param> /// <param name="account">Associated Account</param> /// <param name="addCondition">Construct Account/Contact relationship filter</param> /// <param name="linkEntityAliasGenerator">LinkEntityAliasGenerator to track and create Aliases</param> private static void BuildLinksAndFilter(OrganizationServiceContext serviceContext, ProductAccessProvider.RelationshipMetadata relationshipMetadata, LinkDetails linkDetails, Fetch fetch, Link link, Filter filter, EntityReference contact, EntityReference account, bool addCondition, LinkEntityAliasGenerator linkEntityAliasGenerator) { var alias = linkEntityAliasGenerator.CreateUniqueAlias(relationshipMetadata.Entity2LogicalName); Link newLink = null; if (relationshipMetadata.RelationshipType == ProductAccessProvider.RelationshipType.ManyToManyRelationship) { var intersectLinkEntityName = relationshipMetadata.IntersectEntityName; string linkTargetFromAttribute; string linkTargetToAttribute; string linkIntersectFromAttribute; string linkIntersectToAttribute; if (relationshipMetadata.Entity1LogicalName == relationshipMetadata.Entity2LogicalName) { linkIntersectFromAttribute = relationshipMetadata.Entity2IntersectAttribute; linkIntersectToAttribute = relationshipMetadata.Entity1PrimaryIdAttribute; linkTargetFromAttribute = relationshipMetadata.Entity1PrimaryIdAttribute; linkTargetToAttribute = relationshipMetadata.Entity1IntersectAttribute; } else { linkIntersectFromAttribute = linkIntersectToAttribute = relationshipMetadata.Entity1LogicalName == linkDetails.Entity1Name ? relationshipMetadata.Entity1IntersectAttribute : relationshipMetadata.Entity2IntersectAttribute; linkTargetFromAttribute = linkTargetToAttribute = relationshipMetadata.Entity2LogicalName == linkDetails.Entity2Name ? relationshipMetadata.Entity2IntersectAttribute : relationshipMetadata.Entity1IntersectAttribute; } newLink = new Link { Name = intersectLinkEntityName, FromAttribute = linkIntersectFromAttribute, ToAttribute = linkIntersectToAttribute, Intersect = true, Visible = false, Type = JoinOperator.LeftOuter, Links = new List <Link> { new Link { Name = relationshipMetadata.Entity2LogicalName, FromAttribute = linkTargetFromAttribute, ToAttribute = linkTargetToAttribute, Alias = alias, Type = JoinOperator.LeftOuter } } }; } else if (relationshipMetadata.RelationshipType == ProductAccessProvider.RelationshipType.ManyToOneRelationship) { var linkFromAttribute = relationshipMetadata.ReferencedEntity == relationshipMetadata.Entity2LogicalName ? relationshipMetadata.ReferencedAttribute : relationshipMetadata.ReferencingAttribute; var linkToAttribute = relationshipMetadata.ReferencedEntity == relationshipMetadata.Entity2LogicalName ? relationshipMetadata.ReferencingAttribute : relationshipMetadata.ReferencedAttribute; newLink = new Link { Name = relationshipMetadata.Entity2LogicalName, FromAttribute = linkFromAttribute, ToAttribute = linkToAttribute, Type = JoinOperator.LeftOuter, Alias = alias }; } else if (relationshipMetadata.RelationshipType == ProductAccessProvider.RelationshipType.OneToManyRelationship) { var linkFromAttribute = relationshipMetadata.ReferencedEntity == relationshipMetadata.Entity2LogicalName ? relationshipMetadata.ReferencedAttribute : relationshipMetadata.ReferencingAttribute; var linkToAttribute = relationshipMetadata.ReferencedEntity == relationshipMetadata.Entity2LogicalName ? relationshipMetadata.ReferencingAttribute : relationshipMetadata.ReferencedAttribute; newLink = new Link { Name = relationshipMetadata.Entity2LogicalName, FromAttribute = linkFromAttribute, ToAttribute = linkToAttribute, Type = JoinOperator.LeftOuter, Alias = alias }; } else { throw new ApplicationException(string.Format("Retrieve relationship request failed for relationship name {0}", linkDetails.RelationshipName)); } ContentAccessProvider.AddLink(link, newLink); if (addCondition) // Only add the condition if we are at the end of the chain { var condition = new Condition { Attribute = relationshipMetadata.Entity2PrimaryIdAttribute }; if (linkDetails.Scope.HasValue && linkDetails.Scope.Value == OwningCustomerType.Contact) { condition.EntityName = alias; condition.Operator = ConditionOperator.Equal; condition.Value = contact.Id; } else if (linkDetails.Scope.HasValue && linkDetails.Scope.Value == OwningCustomerType.Account) { condition.EntityName = alias; condition.Operator = ConditionOperator.Equal; condition.Value = account.Id; } else { condition.EntityName = alias; condition.Operator = ConditionOperator.NotNull; } filter.Conditions.Add(condition); } fetch.Distinct = true; }