graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Filtering on nested objects with `HotChocolate.Data` package

Open pxtreme65 opened this issue 2 years ago • 6 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Product

Hot Chocolate

Describe the bug

I apologize in advance if this is not the right location to ask this. I've been having a hard time getting HotChocolate.Data filtering to work on nested objects. I was able to get the old package to work.

When using HotChocolate.Types.Filters package the following query works

query {
  objectA (where: {code_in:[1000,2000]}) {
    id
    friendlyName
    objectB(where: {name_contains:"Clean"}){
      id
      name
    }
  }
}

When using HotChocolate.Data package the nested (objectB) does not work only ObjectA filter works. The EF WHERE Clause is not generated.

query {
  objectA (where: { id: { in: [1000,2000] } }) {
    id
    friendlyName
    objectB(where: {name:{contains:"Clean"}}) {
      id
      name
    }
  }
}

Versions HotChocolate.AspNetCore 13.2.1 HotChocolate.Data 13.2.1 HotChocolate.Data.EntityFramework 13.2.1 Microsoft.EntityFrameworkCore 7.0.7 Microsoft.EntityFrameworkCore.SqlServer 7.0.7

Steps to reproduce

  1. Create schema and implement filtering using HotChocolate.Types.Filters package
  2. Run query and make sure filtering works at multiple levels
  3. Remove HotChocolate.Types.Filters package
  4. Install HotChocolate.Data package
  5. Run same query with the same filtering using HotChocolate.Data package

Relevant log output

No response

Additional Context?

No response

Version

13.2.1

pxtreme65 avatar Jun 15 '23 13:06 pxtreme65

Can you share some resolver code? also do you want to filter the list of objectA's by id and objectB.name or do you want to filter objectA by id and objectB by name ? do you want to do this in one or mutliple db calls?

PascalSenn avatar Jun 16 '23 16:06 PascalSenn

I am having the same issues, hopefully this minimal setup can shed some light into the issue When removing the property from the DTO/POCO it will filter properly, in both scenarios the query will go through the Query and the Node methods.



public class ObjectA {
    public int Id {get;set;}
    //removing this property will allow subcollections to be filtered
    public IEnumerable<ObjectB> Children {get;set;}
}
public class ObjectB {
    public string Name {get;set;}
    public virtual ObjectA Parent {get; set;}
}
[QueryType]
public static class ObjectAQueries {
    
    [UseOffsetPaging]
    [UseSorting]
    [UseFiltering]
    public static IQueryable<ObjectA> GetAs (DbContext dbContext){
        return dbContext.A;
    }
}
[ExtendsObjectType(typeOf(ObjectA))]
public static class ObjectANode {

    [UseOffsetPaging]
    [UseSorting]
    [UseFiltering]
    public static IQueryable<ObjectB> GetChildren([Parent] ObjectA parent, DbContext dbContext){
        return dbContext.B.Where(p=> p.Parent.Id == parent.Id);
    }
}

public class ObjectAType: ObjectType<ObjectA>{
    protected override void Configure(IObjectTypeDescriptor<ObjectA> descriptor)
        {
            descriptor.BindFieldsExplicitly();
            descriptor
                .Field(f => f.Id)
                .IsProjected(true);
                
            descriptor
                .Field(f => f.Children);
                //removing the lambda in favor of a string representation will allow subcollections to be filtered
                //Field("children");
                
        }
}

rbarbosadhc avatar Sep 13 '23 17:09 rbarbosadhc

I ran into the same issue but found that if I set the name of the IQueryable function to be different from the underlying class field filtering works correctly. So in the example above a dirty work around would be to do something like...

[ExtendsObjectType(typeOf(ObjectA))]
public static class ObjectANode {

    [UseOffsetPaging]
    [UseSorting]
    [UseFiltering]
    [GraphQLName("childrenQuery")]
    public static IQueryable<ObjectB> GetChildren([Parent] ObjectA parent, DbContext dbContext){
        return dbContext.B.Where(p=> p.Parent.Id == parent.Id);
    }
}

Changing the node name to something different than the name of the class field worked for me. You will have both nodes in the graph but filtering works on child nodes using childrenQueryable.

chinshaw avatar Sep 18 '23 14:09 chinshaw

I'm having a similar issue. Paging, sorting, filtering and projection work at the root level but not on nested objects. I've attached a .zip to illustrate the issue. I asked on Slack originally (https://hotchocolategraphql.slack.com/archives/CD9TNKT8T/p1718892458760509) and @michaelstaib replied initially and asked me to supply a repro but he hasn't responded since then (probably extremely busy) so I'm mentioning it here too.

Issuing he following query will allow paging/sorting/filtering on the Products but on the nested Options or Option Items.

{
  products(order: {id: ASC}) {
    items {
      id
      name
      options
      ( # take: 1
        where: {name: {eq: "option-a"}}, 
        order: {id: DESC}
      ) {
        items {
          id
          name
          optionItems(order: {price: DESC}) {
            items {
              id
              name
              price
            }
          }
        }
      }
      description
    }
  }
}

filtersort.zip

simax avatar Jul 04 '24 14:07 simax

i have the same issue

daniellondo avatar Aug 04 '24 17:08 daniellondo

I was able to filter on the child property by adding the [UseFiltering] attribute to the Entity.

public class Parent
{
  [UseFiltering]
  public ICollection<Child> Children { get; set; }
}

public class Child
{
  public string Name { get; set; }
}
public class Query
{
    [UseProjection]
    [UseFiltering]
    public IQueryable<Parent> GetParents([Service(ServiceKind.Synchronized)] DataContext context)
    {
        return context.Parents.AsNoTracking();
    }
}

linhub15 avatar Oct 10 '24 18:10 linhub15

I still have the same issues, even when adding [UseFiltering] on the child property as suggested.

The bug is still present in v15.0.3

SeWieland avatar Mar 07 '25 14:03 SeWieland

Its because of the old way we did projections... if you move to the new projections engine you wont have this issue anymore.

The new GreenDonut.Data API bring together DataLoader, projections, filtering and sorting to get more predictable performance and more control over the whole query. At the moment this is available for EF Core and we are working on MongoDB support.

https://www.youtube.com/watch?v=FhNK7KMAnXc

michaelstaib avatar Mar 15 '25 08:03 michaelstaib