/// <summary> /// By default, the server serializer exposes all defined relationships, unless /// in the <see cref="ResourceDefinition{T}"/> a subset to hide was defined explicitly. /// </summary> /// <param name="resourceType">Type of entity to be serialized</param> /// <returns>List of allowed relationships in the serialized result</returns> private List <RelationshipAttribute> GetRelationshipsToSerialize(Type resourceType) { // Check the relationships cache to see if the allowed attrs for this resource type were determined before. if (_relationshipsToSerializeCache.TryGetValue(resourceType, out List <RelationshipAttribute> allowedRelations)) { return(allowedRelations); } // Get the list of relationships to be exposed for this type allowedRelations = _fieldsToSerialize.GetAllowedRelationships(resourceType); // add to cache so we we don't have to look this up next time. _relationshipsToSerializeCache.Add(resourceType, allowedRelations); return(allowedRelations); }
/// <summary> /// Applies include queries /// </summary> protected virtual IQueryable <TResource> ApplyInclude(IQueryable <TResource> entities, RelationshipAttribute chainPrefix = null) { var type = entities.ElementType; var allowedRelations = _fieldsToSerialize.GetAllowedRelationships(type); var chains = _includeService.Get(); var fakeChains = chains.ToList(); // sven // loop through and only add missing ones foreach (var relation in allowedRelations) { // add each allowedRelation to single list because then they get treated separately. // otherwise it would get treated as a follow-up relation bool isIncluded = fakeChains.Select(x => x.First()).Any(x => x.Equals(relation)); if (!isIncluded) { var subList = new List <RelationshipAttribute> { relation }; //var relationType = relation.RightType; //var subAllowed = _fieldsToSerialize.GetAllowedRelationships(relationType); //subList.AddRange(subAllowed); fakeChains.Add(subList); } } if (chainPrefix != null) { chains.Add(new List <RelationshipAttribute>()); } // sven foreach (var inclusionChain in fakeChains) { if (chainPrefix != null) { inclusionChain.Insert(0, chainPrefix); } entities = _repository.Include(entities, inclusionChain); } return(entities); }
/// <summary> /// Gets the resource object for <paramref name="parent"/> by searching the included list. /// If it was not already build, it is constructed and added to the included list. /// </summary> /// <param name="parent"></param> /// <param name="relationship"></param> /// <returns></returns> private ResourceObject GetOrBuildResourceObject(IIdentifiable parent, RelationshipAttribute relationship) { var type = parent.GetType(); var resourceName = _provider.GetResourceContext(type).ResourceName; var entry = _included.SingleOrDefault(ro => ro.Type == resourceName && ro.Id == parent.StringId); if (entry == null) { entry = Build(parent, _fieldsToSerialize.GetAllowedAttributes(type, relationship), _fieldsToSerialize.GetAllowedRelationships(type)); _included.Add(entry); } return(entry); }
/// <summary> /// Builds the values of the relationships object on a resource object. /// The server serializer only populates the "data" member when the relationship is included, /// and adds links unless these are turned off. This means that if a relationship is not included /// and links are turned off, the entry would be completely empty, ie { }, which is not conform /// json:api spec. In that case we return null which will omit the entry from the output. /// </summary> protected override RelationshipEntry GetRelationshipData(RelationshipAttribute relationship, IIdentifiable entity) { RelationshipEntry relationshipEntry = null; List <List <RelationshipAttribute> > relationshipChains = null; relationshipEntry = base.GetRelationshipData(relationship, entity); // sven if (Equals(relationship, _requestRelationship) || ShouldInclude(relationship, out relationshipChains) || true) { if (relationshipChains != null && relationshipChains.Count != 0 && relationshipEntry.HasResource) { // sven //if (relationshipChains.Count == 0) { // relationshipChains = _fieldsToSerialize.GetAllowedRelationships(relationship.RightType) // .Select(x => new List<RelationshipAttribute> { x }).ToList(); //} // every chain in relationshipChains has the same on first position = the relationship requested var allowedRelations = _fieldsToSerialize.GetAllowedRelationships(relationship.RightType); //var fakeChains = relationshipChains.ToList(); var fakeChains = new List <List <RelationshipAttribute> >(); var singleOneIndex = fakeChains.FindIndex(x => x.Count == 1 && x.First().Equals(relationship)); if (singleOneIndex != -1) { fakeChains.RemoveAt(singleOneIndex); } foreach (var relation in allowedRelations) { bool isIncluded = fakeChains.Any(x => x.Last().Equals(relation)); if (!isIncluded) { var subList = new List <RelationshipAttribute> { relationship, relation }; fakeChains.Add(subList); } } // sven foreach (var chain in fakeChains) { // traverses (recursively) and extracts all (nested) related entities for the current inclusion chain. _includedBuilder.IncludeRelationshipChain(chain, entity); } } } var links = _linkBuilder.GetRelationshipLinks(relationship, entity); // sven // omit links everytime //if (links != null) // // if links relationshipLinks should be built for this entry, populate the "links" field. // (relationshipEntry ??= new RelationshipEntry()).Links = links; // if neither "links" nor "data" was populated, return null, which will omit this entry from the output. // (see the NullValueHandling settings on <see cref="ResourceObject"/>) return(relationshipEntry); }