Geoffrey Migliacci
Geoffrey Migliacci

Reputation: 402

OData ASP.Net Core on GET with Id?

I'm trying to [EnableQuery] on a route (User) with id as example if I do a :

GET /users/1?$expand=Character

I'd like to get the User with Id 1 with its Character but currently it returns me null on the character :

{"character":null,"id":1,"username":"Iterer","password":"motdepasse","characterId":1}

But on the (global) route to get all users :

GET /users?$expand=Character

I get the user's character as you can see :

[{"character":{"id":1,"name":"Name"},"id":1,"username":"Iterer","password":"motdepasse","characterId":1}]

Here is my controller's actions :

    // GET: api/Users
    [HttpGet]
    [EnableQuery]
    public ActionResult<IQueryable<UserEntity>> GetUsers()
    {
        return Ok(_context.Users);
    }

    // GET: api/Users/5
    [HttpGet("{id}")]
    [EnableQuery]
    public ActionResult<IQueryable<UserEntity>> GetUserEntity(long id)
    {
        var userEntity = _context.Users.Where(u => u.Id == id).FirstOrDefault();

        if (userEntity == null)
        {
            return NotFound();
        }

        return Ok(userEntity);
    }

Both use IQueryable interface but I still don't understand why it doesn't works, here is the full controller :

https://github.com/myerffoeg/gaium-api/blob/master/Gaium/Controllers/UsersController.cs

and my startup file :

https://github.com/myerffoeg/gaium-api/blob/master/Gaium/Startup.cs

Moreover, if you have some best practices to share it would be appreciated thanks!

Upvotes: 3

Views: 3110

Answers (3)

David Robinson
David Robinson

Reputation: 131

As described by Ivan, your code returns a single materialized Entity. You do need to return the IQueryable<UserEntity>, but as you said in your comment:

return Ok(_context.Users.Where(u => u.Id == id));

Will return an Array with a single entity, not what you want.

You need to tell OData that this query will only return zero or one entity using SingleResult:

return Ok(SingleResult.Create(_context.Users.Where(u => u.Id == id)));

This will return what you want: A single entity(no array), which $expand can be applied.

Upvotes: 0

Ashok Subedi
Ashok Subedi

Reputation: 31

The parameter name should be key instead of id i.e.

    [EnableQuery]
    public IActionResult Get(int key)
    {
       return Ok(_repository.Get(key));
    }

Upvotes: 3

Ivan Stoev
Ivan Stoev

Reputation: 205589

Both use IQueryable interface but I still don't understand why it doesn't works

Well, the difference is that while to "non working" method claims to return IQueryable<UserEntity>:

public ActionResult<IQueryable<UserEntity>> GetUserEntity(long id)

the implementation returns single materialized UserEntity instance.

In order to match the claim, the implementation should be like this instead (basically the first method with Where clause applied):

return Ok(_context.Users.Where(u => u.Id == id));

Upvotes: 3

Related Questions