1

Working with ASP.NET Core and OData v4

I get a

InvalidOperationException: The path template 'Classes({key})/Bookings({bookingKey})' on the action 'GetBooking' in controller 'Classes' is not a valid OData path template. Bad Request - Error in query syntax.

I don't see the error in query syntax. Here is the full code of this method in my controller 'Classes'

    /// <summary>
    /// Get a specific booking
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [ODataRoute("Classes({key})/Bookings({bookingKey})")]
    public async Task<IActionResult> GetBooking([FromODataUri] Guid key, [FromODataUri] Guid bookingKey)
    {
        var @class = await _context.Classes.FirstOrDefaultAsync(y => y.Id == key);

        if (@class == null)
        {
            return NotFound();
        }

        var booking = _context.Bookings.Where(y => y.Class.Id == key && y.Id == bookingKey);

        if (!booking.Any())
        {
            return NotFound();
        }

        return Ok(SingleResult.Create(booking));
    }

This method is defined in 'Classes' Controller. I also have a GeBookings method and 2 actions methods defined that cause no issue. When I comment my GetBooking() method I don't have any error.

Booking is a [Contained] ICollection of Booking

public class Class
{
    [Key]
    public Guid Id { get; set; }

    // Others properties

    [Contained]
    public ICollection<Booking> Bookings {get; set;}
}

I really see my error. Were should I look?

EDIT More information

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="Oyg" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="Owner">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Name" Type="Edm.String" />
                <Property Name="Email" Type="Edm.String" />
                <Property Name="PhoneNumber" Type="Edm.String" />
                <Property Name="Hash" Type="Edm.String" />
                <Property Name="ConfigurationString" Type="Edm.String" />
                <NavigationProperty Name="Teachers" Type="Collection(Oyg.Teacher)" ContainsTarget="true" />
                <NavigationProperty Name="Locations" Type="Collection(Oyg.Location)" ContainsTarget="true" />
                <NavigationProperty Name="Classes" Type="Collection(Oyg.Class)" ContainsTarget="true" />
            </EntityType>
            <EntityType Name="Student">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Name" Type="Edm.String" />
                <Property Name="Email" Type="Edm.String" />
                <Property Name="PhoneNumber" Type="Edm.String" />
                <Property Name="Hash" Type="Edm.String" />
                <Property Name="ConfigurationString" Type="Edm.String" />
            </EntityType>
            <EntityType Name="Class">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Title" Type="Edm.String" />
                <Property Name="Description" Type="Edm.String" />
                <Property Name="StartTime" Type="Edm.DateTimeOffset" Nullable="false" />
                <Property Name="EndTime" Type="Edm.DateTimeOffset" Nullable="false" />
                <Property Name="Status" Type="Oyg.ScheduleStatus" Nullable="false" />
                <Property Name="Positions" Type="Edm.Int32" Nullable="false" />
                <Property Name="Bookings" Type="Collection(Oyg.Booking)" />
                <NavigationProperty Name="Owner" Type="Oyg.Owner" />
                <NavigationProperty Name="Teacher" Type="Oyg.Teacher" />
                <NavigationProperty Name="Location" Type="Oyg.Location" />
            </EntityType>
            <ComplexType Name="Booking">
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Position" Type="Edm.Int32" Nullable="false" />
                <Property Name="ReservationTime" Type="Edm.DateTimeOffset" Nullable="false" />
                <Property Name="CancelTime" Type="Edm.DateTimeOffset" />
                <NavigationProperty Name="Class" Type="Oyg.Class" Nullable="false" />
                <NavigationProperty Name="Student" Type="Oyg.Student" Nullable="false" />
            </ComplexType>
            <EntityType Name="Teacher">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Name" Type="Edm.String" />
                <Property Name="Description" Type="Edm.String" />
                <Property Name="Email" Type="Edm.String" />
                <Property Name="PhoneNumber" Type="Edm.String" />
                <Property Name="Website" Type="Edm.String" />
                <NavigationProperty Name="Owner" Type="Oyg.Owner" />
            </EntityType>
            <EntityType Name="Location">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Title" Type="Edm.String" />
                <Property Name="Description" Type="Edm.String" />
                <Property Name="Geolocalisation" Type="Edm.String" />
                <Property Name="Address" Type="Edm.String" />
                <Property Name="Facilities" Type="Edm.String" />
                <NavigationProperty Name="Owner" Type="Oyg.Owner" />
            </EntityType>
            <EnumType Name="ScheduleStatus">
                <Member Name="Draft" Value="0" />
                <Member Name="Published" Value="1" />
                <Member Name="Cancelled" Value="2" />
            </EnumType>
            <EntityContainer Name="OygContainer">
                <EntitySet Name="Owners" EntityType="Oyg.Owner" />
                <EntitySet Name="Students" EntityType="Oyg.Student" />
                <EntitySet Name="Classes" EntityType="Oyg.Class">
                    <NavigationPropertyBinding Path="Bookings/Class" Target="Classes" />
                    <NavigationPropertyBinding Path="Bookings/Student" Target="Students" />
                    <NavigationPropertyBinding Path="Owner" Target="Owners" />
                </EntitySet>
            </EntityContainer>
        </Schema>
        <Schema Namespace="Oyg.Actions" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <Action Name="Register" IsBound="true">
                <Parameter Name="bindingParameter" Type="Oyg.Class" />
                <Parameter Name="studentId" Type="Edm.Guid" Nullable="false" />
                <ReturnType Type="Oyg.Booking" />
            </Action>
            <Action Name="CancelRegistration" IsBound="true">
                <Parameter Name="bindingParameter" Type="Oyg.Class" />
                <Parameter Name="studentId" Type="Edm.Guid" Nullable="false" />
            </Action>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

It seems my ICollection of Booking is not considered as a contained navigation property byt really like a collection

{
    "@odata.context": "https://localhost:44375/odata/$metadata#Classes",
    "value": [
        {
            "Id": "dde8de4d-89ca-4ba3-cff7-08d6aac63c0f",
            "Title": "xxx",
            "Description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            "StartTime": "2019-02-24T18:00:00+08:00",
            "EndTime": "2019-02-24T19:00:00+08:00",
            "Status": "Draft",
            "Positions": 22,
            "Bookings": []
        }
    ]
}
3
  • This error happens when I start my web API. Commented Mar 26, 2019 at 16:32
  • can you share your startup class Commented Apr 3, 2019 at 17:40
  • I will give you the link about the same question on GitHub Repository of main OData project: github.com/OData/WebApi/issues/1789. There is much more code. I just see I received an answer, do you confirm? I will try it later today. Commented Apr 4, 2019 at 3:58

1 Answer 1

1

Answer coming from xuzhg https://github.com/OData/WebApi/issues/1789

Bookings is configured as "Structural property" and its type is complex type. Complex type is structural type without key,therefore, your path template 'Classes({id})/Bookings({bookingId})' can't work.

The root cause is the call "registerAction.Returns()", this line will configure the "Booking" type as complex type. I think if you call "registerAction.ReturnsFromEntitySet("Bookings")" can resolve the problem. Thanks

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.