Search code examples
entity-frameworkasp.net-web-apiodata

Web Api 2 - OData v3 - insert many-to-many table odata query


I'm trying to insert a many-to-many table with web api odata controls.

Db scheme

model

And I' ve created controls with scaffolding odata controllers with ef. Everything is great. I can query the user table like this:

GET http://localhost:51875/odata/Users(1)?$expand=Roles

{
    "odata.metadata": "http://localhost:51875/odata/$metadata#Users/@Element",
    "Roles": [
        {
            "ID": 20,
            "Name": "Admin"
        }
    ],
    "ID": 1,
    "UserName": "user",
    "Password": "pass",
    "EnteredDate": "2017-12-07T14:55:22.24",
    "LastLoginDate": null,
    "Active": true
}

I've inserted the record 'Admin' manually. How can I add a new role for user?

I've tried,

PATCH http://localhost:51875/odata/Users(1)

{
    "Roles": [
        {
            url : "http://localhost:51875/odata/Roles(10)"
        }
    ],
}

it did not work. Can you help me?


Solution

  • Bit late perhaps but there is an answer to this, it is described on: learn.microsoft.com/...

    Add the following CreateRef method to your UserController:

    [AcceptVerbs("POST", "PUT")]
    public IHttpActionResult CreateRef([FromODataUri] int key, string navigationProperty, [FromBody] Uri link)
    {
        var user = Db.Users
                .FirstOrDefault(p => p.Id == key); //Get User by id
        if (user == null)
        {
            return NotFound();
        }
    
        switch (navigationProperty)
        {
            case "Roles":
                // You'll have to impement this 'getkey' method somehow.
                // You could implement it yourself or take a look on the webpage I linked earlier.
                var relatedKey = GetKeyFromUri(link);
                var role = Db.Roles
                        .FirstOrDefault(f => f.Id == relatedKey); //Get Role by id
                if (role == null)
                {
                    return NotFound();
                }
    
                user.Roles.Add(role);
                break;
    
            default:
                return StatusCode(HttpStatusCode.NotImplemented);
        }
        Db.SaveChanges();
        return StatusCode(HttpStatusCode.NoContent);
    }
    

    Now you can add roles to a user with the following HTTP request:

    PUT [...]/api/User(2)/Roles/$ref
    Content-Type: application/json
    Content-Length: 54
    { "@odata.id": "[...]/api/Role(4)/" }
    

    Personally I don't find this method particularly nice but it is the standard. You could also do this with a custom 'AddRoles' action as you mention in your comment.