Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate valid id/read/edit links for expanded non-contained resource with a contained navigation source #1088

Conversation

gathogojr
Copy link
Contributor

@gathogojr gathogojr commented Nov 9, 2023

This pull request fixes OData/odata.net#2273.

Description

In the described scenario, a Site entity type has a contained Plants navigation property. The Plant entity type in turn has a contained Pipelines navigation property. The Pipeline entity type in turn has a non-contained single-valued Plant navigation property.

The non-contained Plant navigation property is bound to the Plants contained entity set via the Edm path Sites/Plants:

namespace Core
{
    public abstract class EntityBase
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public Dictionary<string, object>? Attributes { get; set; }
    }

    public class Site : EntityBase
    {
        [Contained]
        public IEnumerable<Plant>? Plants { get; set; }
    }

    public class Plant : EntityBase
    {
        public Site Site { get; set; }
        [Contained]
        public IEnumerable<PipelineBase> Pipelines { get; set; }
    }

    public abstract class PipelineBase : EntityBase
    {
        public Plant Plant { get; set; }
    }
}

namespace Plant1
{
    public class Pipeline : PipelineBase
    {
        public int? Length { get; set; }
    }
}

The Sites entity set and the navigation property bindings are as follows:

<EntitySet Name=""Sites"" EntityType=""Core.Site"">
    <NavigationPropertyBinding Path=""Plants/Pipelines/Plant"" Target=""Sites/Plants""/>
    <NavigationPropertyBinding Path=""Plants/Site"" Target=""Sites""/>
</EntitySet>

If the $format or Accept request headers specify odata.metadata=full, and we attempt to expand the Plant navigation property, i.e., /Sites(1)/Plants(1)/Pipelines(1)?$expand=Plant - where Plant is non-contained, failure to use the link builder to build the id/read/edit links results into invalid links since we generate the links by appending /Plants(1) to the parent Pipeline resource id - /Sites(1)/Plants(1)/Pipelines(1) => /Sites(1)/Plants(1)/Pipelines(1)/Plants(1). This link is invalid since there's no Plants navigation property on Pipeline entity type.

The following line causes us not to use the link builder to generate the id/read/edit links if the resourceContext.NavigationSource is a contained entity set:

if (!(resourceContext.NavigationSource is IEdmContainedEntitySet))

This PR fixes the issue by causing the link builder to be used if resourceContext.NavigationSource is a contained entity set and an expanded non-contained resource is being written. A navigation property binding should exist and a navigation link builder should be on hand to build the links.

Tests verify that expected behaviour is observed even when the non-contained navigation property is in a nested expand.

Checklist (Uncheck if it is not completed)

  • Test cases added
  • Build and test with one-click build and test script passed

@gathogojr gathogojr force-pushed the fix/odl-2273-invalid-metadata-properties-for-expanded-nav-property branch 2 times, most recently from 7e1560e to 071f640 Compare November 10, 2023 11:30
xuzhg
xuzhg previously approved these changes Nov 10, 2023
@gathogojr gathogojr force-pushed the fix/odl-2273-invalid-metadata-properties-for-expanded-nav-property branch 2 times, most recently from e3180be to 6069bdb Compare November 12, 2023 06:11
@@ -0,0 +1,98 @@
//-----------------------------------------------------------------------------
// <copyright file="DollarExpandController.cs" company=".NET Foundation">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name doesn't really give an overview of what these tests are for.. Use a more descriptive name for this scenario for all the files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ElizabethOkerio What would you propose?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LinksForExpandedResourcesWithContainedNavSources .. this is too long but something in those lines.

Copy link
Contributor Author

@gathogojr gathogojr Nov 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ElizabethOkerio None of the existing directories that categorize tests under it has this level of detail - LinksForExpandedResourcesWithContainedNavSources. The directory name is a just pointer to the kind of tests one should expect under it. I renamed the directory to MetadataProperties which in essence is what the fix is all about. The tests are a combination of many scenarios (contained properties, non-contained properties, expanded navigation properties, nested expansion, etc.) - and tests for more scenario could be added with time. The key thing we're testing is that the generated metadata properties (@odata.id, @odata.editLink, @odata.associationLink, @odata.navigationLink, etc.) are valid.

Assert.EndsWith($"{plantResourceBase}", plant.Value<string>("@odata.editLink"));
Assert.Equal(1, plant.Value<int>("Id"));
Assert.Equal("Plant 1", plant.Value<string>("Name"));
Assert.EndsWith($"{scenario}/{plantResourceBase}/Site/$ref", plant.Value<string>("[email protected]"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here there's no type segment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@habbes There shouldn't be a type segment there. The Site navigation property is not initialized to a derived type as is the case for the Pipelines navigation property.

@gathogojr gathogojr force-pushed the fix/odl-2273-invalid-metadata-properties-for-expanded-nav-property branch from 6069bdb to 3c2dd70 Compare November 16, 2023 05:30
@gathogojr gathogojr merged commit 539096f into OData:main Nov 17, 2023
2 checks passed
@gathogojr gathogojr deleted the fix/odl-2273-invalid-metadata-properties-for-expanded-nav-property branch November 17, 2023 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid OData control annotations for expanded navigation property
4 participants