0

I'm new to using GraphQL/Hot Chocolate and I've been struggling with something that I hope someone here can help me with. I'm going with the code-first approach using F#. I have a type called Employee that has a one-to-many relationship with another type called PersonalValue. I've got everything set up in EF Core to bring back the list of of PersonalValues. I'm also wanting to map a property to the Employee type that is the current value (the current active Personal Value is deteremined by EndDate = NULL in the database). How would I go about adding this? I couldnt find a way to make this mapping using EF Core so I tried a couple of different options.

I tried adding a read-only property called PersonalValue which just filtered out the PersonalValues to a single record. This did work however when I try to do any filtering on it, I get a LINQ error.

member this.PersonalValue with get() = this.PersonalValues.Where(fun x -> not(x.EndDate.HasValue)).FirstOrDefault()

Gives this nasty error

The LINQ expression 'DbSet<Employee>()\r\n    .Where(e => e.PersonalValue.LastName != null && e.PersonalValue.LastName.Contains(__p_0) && e.EmployeeID > __p_1)' could not be translated. Additional information: Translation of member 'PersonalValue' on entity type 'Employee' failed. This commonly occurs when the specified member is unmapped.\r\nTranslation of member 'PersonalValue' on entity type 'Employee' failed. This commonly occurs when the specified member is unmapped. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync

I also tried adding a function to my Employee type to resolve a single PersonalValue

member this.GetPersonalValue(): PersonalValue = 
    this.PersonalValues
        .Where(fun x -> not(x.EndDate.HasValue))
        .FirstOrDefault()

This also works for a basic query, but now the schema doesnt show a filter for PersonalValue anymore.

I would really appreciate some help. The TLDR is I'm trying to figure out how can I add a property to a type that is resolved from another property and is filterable.

Thanks in advance!

Edit: I also wanted to share my query as an example

query {
    employees(
        first: 50
        where: {
      personalValue: {
        lastName: {contains: "John"}
      }
        }
    ) {
        nodes {
            employeeID
            personalValue {employeeID lastName firstName}
        }
    }
}
abaga129
  • 887
  • 1
  • 9
  • 12
  • Just curious, why are you using LINQ here? – Jim Foye May 03 '23 at 18:56
  • @JimFoye Is there a better way to get that single item? I was just trying to find a way to get a property that represents a single item out of the list of items. It does seem like LINQ is part of my issue because it is trying to add to the query that gets sent to the database. – abaga129 May 03 '23 at 19:08
  • I attempted to rewrite this without using LINQ but it still seems like Hot Chocolate tries to turn my filter into a LINQ expression. I understand now that the issue is that when I do add a filter based on this extra property, HotChocolate is trying to turn that into a LINQ expression to run against my database using EF Core. Hot Chocolate seems to have no way to know that the property is not mapped to the entity in the DbContext. – abaga129 May 03 '23 at 19:21
  • Ah, sorry, I didn't realize there was a database call involved (yeah, I should have seen that, I was just focused on the code in the member, thought that was LINQ on in memory object). – Jim Foye May 03 '23 at 21:01

1 Answers1

0

So ended up finding a way to make this work based on a suggestion from a colleague of mine. It isnt ideal but what I had to do was the following.

  1. Create a view that filtered down the table that I wanted to join with a one-to-one relationship
  2. Move my entity type definition into a base class that held all of the properties
  3. Create two sub-classes of that base type. One to represent the one-to-many relationship and another to represent the one-to-one relationship. (These clases are identitical aside from having different names. This is just necessary for EF Core to do the mappings)
  4. In my DbContext set up the mappings for each entity type.

In the end the problem and solution ended up being entirely on the Entity Framework side of things. There still may have been a way to achieve the same result using resolvers in Hot Chocolate but I could not find a way with my limited knowledge. The upside of doing it this way is that it is very fast since it all gets filtered at the database level.

abaga129
  • 887
  • 1
  • 9
  • 12