Search code examples
javaodataodata-v4olingo

Bi-directional navigation in OData V4


* I will accept the answer with bounty if it just solves my problem (if you don't have a detailed canonical solution) *

When i try to access the metadata from browser (http://......Service.svc/$metadata), I see below error.

500 Cannot find navigation property with name: projectConfigs at type ProjectConfig

I am trying to design a bi-directional association in OData v4 (I am using Partner, any other way available?!). I am not sure what is the mistake I am doing while implementing it.

I have two classes namely “Project” and “ProjectConfig”. I need navigation from Project to ProjectConfig and vice-versa. The idea is that for a defined Project, I should be able to see the ProjectConfig(urations) and from there I want navigation back to the Project it belongs to.

I am using Olingo framework for writing application code. This is the example i followed.

The challenge i see in this example is that navigation name "Products" and EntitySet name "Products" are same.

To my understanding when we define partner on a navigation, we should be able to find a property with the same name in the "Nav Type". This will ideally setup the navigation back to the entitytype.

I have pasted the metadata and java application code that is of interest.

metadata.xml

<EntityType Name="Project">
    <Key>
        <PropertyRef Name="id"/>
    </Key>
    <Property Name="id" Type="Edm.Int32"/>
    <Property Name="name_artifact_id" Type="Edm.String"/>
    <Property Name="groupid" Type="Edm.String"/>
    <Property Name="project_display_name" Type="Edm.String"/>

    <NavigationProperty Name="projectConfigs"
                        Type="Collection(devplatform.config.ProjectConfig)"
                        Partner="project"/>
</EntityType>

<EntityType Name="ProjectConfig">
    <Key>
        <PropertyRef Name="id"/>
    </Key>
    <Property Name="id" Type="Edm.Int32"/>

    <NavigationProperty Name="project"
                        Type="devplatform.config.Project"
                        Partner="projectConfigs"/>
</EntityType>

<EntitySet Name="Projects" EntityType="devplatform.config.Project">
    <NavigationPropertyBinding Path="ProjectConfigs" Target="ProjectConfigs"/>
</EntitySet>

<EntitySet Name="ProjectConfigs" EntityType="devplatform.config.ProjectConfig">
    <NavigationPropertyBinding Path="Projects" Target="Projects"/>
</EntitySet>

DemoEdmProvider.java

public static void main(String[] args) {
public static final String ET_PROJECT_NAME = "Project";
public static final FullQualifiedName ET_PROJECT_FQN = 
        new FullQualifiedName(NAMESPACE, ET_PROJECT_NAME);

public static final String ET_PROJECTCONFIG_NAME = "ProjectConfig";
public static final FullQualifiedName ET_PROJECTCONFIG_FQN = 
        new FullQualifiedName(NAMESPACE, ET_PROJECTCONFIG_NAME);

public static final String ES_PROJECTS_NAME = "Projects";
public static final String ES_PROJECTCONFIGS_NAME = "ProjectConfigs";

public static final String NAV_TO_PROJECT = "Project";
public static final String NAV_TO_PROJECTCONFIG = "ProjectConfig";


if (entityTypeName.equals(ET_PROJECT_FQN)) {
    List<CsdlProperty> propertyList = new ArrayList<CsdlProperty>();
    // create EntityType properties
    CsdlProperty id = 
            new CsdlProperty().setName("id")
                              .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
    propertyList.add(id);
    CsdlProperty name_artifact_id = 
            new CsdlProperty().setName("name_artifact_id")
                              .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
    propertyList.add(name_artifact_id);
    CsdlProperty groupid = 
            new CsdlProperty().setName("groupid")
                              .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
    propertyList.add(groupid);
    CsdlProperty project_display_name = 
            new CsdlProperty().setName("project_display_name")
                              .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
    propertyList.add(project_display_name);


    // create PropertyRef for Key element
    CsdlPropertyRef propertyRef = new CsdlPropertyRef();
    propertyRef.setName("id");

    // navigation property: many-to-one, null not allowed (product must have a category)
    List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();

    CsdlNavigationProperty projectconfigs = 
            new CsdlNavigationProperty().setName(NAV_TO_PROJECTCONFIGS)
                                        .setType(ET_PROJECTCONFIG_FQN)
                                        .setCollection(true)
                                        .setPartner("projectConfigs");
    navPropList.add(projectconfigs);


    // configure EntityType
    entityType = new CsdlEntityType();
    entityType.setName(ET_PROJECT_NAME);
    entityType.setProperties(propertyList);
    entityType.setKey(Arrays.asList(propertyRef));
    entityType.setNavigationProperties(navPropList);
}

if (entityTypeName.equals(ET_PROJECTCONFIG_FQN)) {
    List<CsdlProperty> propertyList = new ArrayList<CsdlProperty>();
    // create EntityType properties
    CsdlProperty id = 
            new CsdlProperty().setName("id")
                              .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
    propertyList.add(id);

    // create PropertyRef for Key element
    CsdlPropertyRef propertyRef = new CsdlPropertyRef();
    propertyRef.setName("id");

    // navigation property: many-to-one, null not allowed (product must have a category)
    List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();

    // ERROR CAUSING LINE
    CsdlNavigationProperty project = 
            new CsdlNavigationProperty().setName(NAV_TO_PROJECT)
                                        .setType(ET_PROJECT_FQN)
                                        .setNullable(true)
                                        .setPartner("project");
    navPropList.add(project);

    // configure EntityType
    entityType = new CsdlEntityType();
    entityType.setName(ET_PROJECTCONFIG_NAME);
    entityType.setProperties(propertyList);
    entityType.setKey(Arrays.asList(propertyRef));
    entityType.setNavigationProperties(navPropList);
}

I can provide any missing details if needed! :) Could not get responses! Not sure, if my question is relevant to a small community!!


Solution

  • I guess the root of the issue is in the different case of characters used for NavigationProperty names and NavigationPropertyBinding paths. Consider using upper camel case for all property names.

    There is also another problem in using path Projects (in plural) for navigation property binding of the entity set ProjectConfigs while naming the navigation property of the ProjectConfig as project (in singular).