question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Handling query string parameters without EF Core

See original GitHub issue

From https://gitter.im/json-api-dotnet-core/Lobby?at=634e9e31a3ccb16cbe13f782:

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 18 14:38

Hello everyone, I am trying to use JsonApiDotNetCore without EntityFramework, on an already existing database (and on which I cannot change the structure). I have tables that don’t have a unique id, but are composed of the parent key + a child key. What is the best practice to build my resources? Can I define a “Tid” with a multi-value key?

Here is a simple example in a database

Persons : ID NAME 1 Ryder 2 Joe 3 William

Dogs PARENTID | ID | DOG 1 | 1 | Rubble 1 | 2 | Marshall 2 | 1 | Rocky

How would you build the resource classes?

Bart Koelman @bkoelman Oct 18 18:48

If you’d use EF Core, we have a sample that shows how to handle composite PKs at https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/CompositeKeys. But if you don’t use EF Core, then you’re responsible for implementing logic to query the database yourself, so you can do it in any way you want.

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 19 11:22

Hi Bart and thanks for the quick response! I had also thought of an implementation based on key concatenation, so I’ll go with that. I have another question, again because of the fact that I’m not using entity, how do I intercept the parameters passed by filters and sorts? Is it in JsonApiResourceDefinition? Because OnApplySort and OnApplyFilter seem not to be called, while OnApplySparseFieldSet is called when i use expected query args.

Bart Koelman @bkoelman [Oct 19 13:16]

See json-api-dotnet/JsonApiDotNetCore#1181, which shows how to access parsed query string parameters. When not using EF Core, you’ll need to make the appropriate calls into resource definitions yourself (via injected IResourceDefinitionAccessor). The reason you’re seeing OnApplySparseFieldSet being called is because the response serializer throws out any additional fields that were retrieved from database, but should not be returned. Normally it is called twice, the first time allowing to fetch additional fields from DB, typically if there are calculated properties whose value depends on another property that isn’t requested.

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 20 00:55

Thank you! My mistake was to extract the expressions in the service constructor, but it seems that the analysis is not yet done at that time. By doing the expression extraction in each service command, I get the data passed in the url. I need now to create my own base service class, have to include the expression parsing + definition event calls + calls to my custom repository. Great job anyway, great framework!

Bart Koelman @bkoelman Oct 20 03:54

Thanks!

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 22 00:38

Hello, I have a new problem, I have integrated a property exposed with a relation [HasMany] in my entity. When I try to load via http://route/1?include=myproperty the json flow response returns “included”: [] while my object is correctly instantiated on the c# side, I can’t understand what’s wrong, is it a problem with the serialization options? The uri seems to be well interpreted because if I fill a bad value in myproperty, I have an error. I have the problem with a [HasOne] attribute too. Any suggestions?

Bart Koelman @bkoelman Oct 22 01:47

I would guess you didn’t populate the relationship property with objects retrieved from the database, but it’s hard to say without more info. Can you create an issue with minimal repro steps?

Bart Koelman @bkoelman Oct 22 01:50

Alternatively, you can step into the source code from our NuGet while debugging, see the next link on how to use: https://devblogs.microsoft.com/dotnet/improving-debug-time-productivity-with-source-link/

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 23 10:06

My entities :

public class Person : Identifiable<int>
{
    [Attr]
    public string Name { get; set; }
    [Attr]
    public int Age { get; set; }
    [HasMany]
    ICollection<Dog> Dogs { get; set; }
}

public class Dog : Identifiable<string>
{
    [HasMany]
    public Person Owner { get; set; }
    [Attr]
    public string Name { get; set; }
}

public class Program
{
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddJsonApi(opt =>
    {
        opt.SerializerOptions.WriteIndented = true;
        opt.RelationshipLinks = JsonApiDotNetCore.Resources.Annotations.LinkTypes.All;
        opt.DefaultAttrCapabilities = JsonApiDotNetCore.Resources.Annotations.AttrCapabilities.All;
        opt.ResourceLinks = JsonApiDotNetCore.Resources.Annotations.LinkTypes.All;
        opt.TopLevelLinks= JsonApiDotNetCore.Resources.Annotations.LinkTypes.All;
    },
    discovery =>
    {
        discovery.AddCurrentAssembly();
    });

    builder.Services.AddScoped<IResourceService<Person, int>, PersonService>();
    builder.Services.AddScoped<IResourceService<Dog, string>, DogService>();
    builder.Services.AddScoped<IDogRepository, DogRepository>();
    builder.Services.AddScoped<IPersonRepository, PersonRepository>();
    var app = builder.Build();

    app.UseRouting();
    app.UseJsonApi();
    app.MapControllers();

    app.Run();
}

public class PersonService : IResourceService<Person, int>
{  
    IPersonRepository repo;

    public PersonService(IPersonRepository repo)
    {
        repo = _repo;
    }

    public Task<Person> GetAsync(int id, CancellationToken cancellationToken)
    {
        return Task.Run(() => { return repo.GetByID(id); });
    }

    public Task<IReadOnlyCollection<Person>> GetAsync(CancellationToken cancellationToken)
    {

        return Task.Run(() => { return repo.GetAll(); });
    }
    // ...
}

public class DogService : IResourceService<Dog, string>
{
    IDogRepository _repo;

    public DogService(IDogRepository repo)
    {
        _repo = repo;
    }

    public Task<Dog> GetAsync(string id, CancellationToken cancellationToken)
    {
        return Task.Run(() => { return repo.GetById(id); });
    }

    public Task<IReadOnlyCollection<Dog>> GetAsync(CancellationToken cancellationToken)
    {
        return Task.Run(() => { return _repo.GetAll(); }); 
    }
    // ...
}

Alexandre DOMS @Alexandre.D-IdemSante_gitlab Oct 23 10:12

I tried to debug it, when calling http://route/Dogs/1?include=owner, but i saw nothing, i think it’s in the ResponseModelAdapter, when Convert function is called, especially when document.Included = GetIncluded(rootNode); is called.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
Alex-Domscommented, Nov 23, 2022

Thanks, I finally figured it out on my end too: I find the instance of IIncludeQueryStringParameterReader and extracte the IncludeExpression from it. Just add it to the IEvaluatedIncludeCache instance and it works.

0reactions
bkoelmancommented, Nov 22, 2022

IncludeExpression contains a set of subtrees. You can build your own (example here) or just feed a string to IncludeParser (example here).

In general, many questions you can find the answer for by searching for usages in our codebase, or debugging a test to see how things look like. We have excellent coverage for all kinds of things, just a small subset is in the documentation website.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Handling query string parameters with no value in ASP.NET ...
In this case, the converter is a BooleanConverter , which doesn't recognize an empty value… It will return our model binder if the...
Read more >
Access Query string parameters with no values in ASP.NET
To retrieve all such query parameters you use Request.QueryString.GetValues(null) to retrieve them as an array of strings, or you can use ...
Read more >
Using Query String Parameters with Minimal APIs
In this article, we will explain the various ways we can work with query string parameters in Minimal APIs in .Net 6.
Read more >
How to Read Values From Query Strings In ASP.NET Core
In this article, we are going to learn how to read values from query strings in ASP.NET Core. We'll see different examples to...
Read more >
Required Query String Parameters in ASP.NET Core
Hello guys, I am trying to set the query string parameters required like below; [Authorize] [HttpGet] ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found