OData 4.0: Referential constraint when principal key is defined in base class

Bernd 0 Reputation points
2023-02-24T09:22:53.97+00:00

Hello,

I am implementing an OData v.4.0 web service using the latest version 7.6.4 and I use the Non-Convention model builder to create my EDM model.

I have a base class Person with a Derived class Customer. The Customer class is related to the Order class in a one to many relationship where a customer can have many orders and an order has one customer.

Person

  • Id : Guid (Key)

Customer : Person

  • Orders : Collection<Order>

Order

  • Id : Guid (Key)
  • Customer : Customer
  • CustomerId : Guid (Foreign Key)

I create an entity set and entity type for all the types above and I specified the inheritance like this:

customerTypeConfig.DerivesFrom(personTypeConfig);

Key properties are defined in Person and in Order:

entityTypeConfig.HasKey(entityType.GetProperty("Id"));

I also define a navigation property in the Order class and want to set up a referential constraint:

NavigationPropertyConfiguration nav =                                   orderEntityTypeConfig.AddNavigationProperty(customerPropertyInfo, EdmMultiplicity.ZeroOrOne);
orderEntitySetConfig.AddBinding(nav, customerEntitySetConfig);
nav.HasConstraint(customerIdPropertyFromOrderClass, idPropertyFromCustomerClass);

With this setup I get the following exception:

System.ArgumentException: "Cannot redefine property 'Id' already defined on the base type 'Module.BusinessObjects.Person'. It does not matter whether the ReflectedType of the principal PropertyInfo is Customer or Persion - I tried it both ways.

Here is the stack trace:

> Microsoft.AspNet.OData.dll!Microsoft.AspNet.OData.Builder.StructuralTypeConfiguration.ValidatePropertyNotAlreadyDefinedInBaseTypes(System.Reflection.PropertyInfo propertyInfo) Zeile 674 C#

Microsoft.AspNet.OData.dll!Microsoft.AspNet.OData.Builder.StructuralTypeConfiguration.AddProperty(System.Reflection.PropertyInfo propertyInfo) Zeile 309 C#

Microsoft.AspNet.OData.dll!Microsoft.AspNet.OData.Builder.NavigationPropertyConfiguration.HasConstraint(System.Collections.Generic.KeyValuePair<System.Reflection.PropertyInfo, System.Reflection.PropertyInfo> constraint) Zeile 256 C#

Microsoft.AspNet.OData.dll!Microsoft.AspNet.OData.Builder.NavigationPropertyConfiguration.HasConstraint(System.Reflection.PropertyInfo dependentPropertyInfo, System.Reflection.PropertyInfo principalPropertyInfo) Zeile 221 C#

If I just remove the refererential constraint then the model is setup correctly and the service works as expected.

If I remove the inheritance for testing purposes and I define the key in the Customer class instead, then the constraint works fine as well.

How do I define this constraint correctly?

Thanks and regards

Bernd

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,347 questions
ASP.NET API
ASP.NET API
ASP.NET: A set of technologies in the .NET Framework for building web applications and XML web services.API: A software intermediary that allows two applications to interact with each other.
293 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. XuDong Peng-MSFT 10,096 Reputation points Microsoft Vendor
    2023-02-27T06:24:05.57+00:00

    Hi @Bernd,

    Based on your description, I'm a little confused about your design.

    Order

    • Id : Guid (Key)
    • Customer : Customer
    • CustomerId : Guid (Foreign Key)

    As the bold part, you have defined the Customer property in the Order class, but why did you define the CustomerId property again? You can directly get the CustomerId value from the Customer object. But if you define it to do something else, can you clarify more details?

    In this case, I think you can use the Customer property in Order class as the navigation property.

    Best regards,

    Xudong Peng


    If the answer is the right solution, please click "Accept Answer" and kindly upvote. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Bernd 0 Reputation points
    2023-06-15T10:04:02.63+00:00

    I was able to solve the issue. The core of the problem arises when trying to setup a contstraint for a navigation property like this:

    myNavigationPropertyConfiguration.HasConstraint(myDependantPropertyInfo, myPrincipalPropertyInfo);
    

    This causes an exception, if 'myPrincipalPropertyInfo' (which is the id property) is defined in a base class of the class where the navigation property points to.

    Why? The API tries to find the property, and if it does not exist in the exact class, it tries to add a property configuration. Then it checks if the property is already defined in a base class, and if so, the exception occurs.

    In my mind, this is a bug in the implementation of 'HasConstraint', which should also check if the property is defined in a base class and if so, not try to add the property.

    Solution:

    Wait with the definition of the type inheritance of the model until all navigation properties and constraints are defined. Then, remove the properties from the derived class and as a last step, setup the inheritance:

    derivedType.RemoveProperty(derivedType.ClrType.GetProperty("MyIdProperty"));
    
    0 comments No comments