0

I have a data model ItemData as follows :

class ItemData
{
  public string StartTime { get; set; }
  public string EndTime { get; set; }
  // other fields here
}

I would like to expose those two as a single field Duration like this. Without exposing the StartTime and EndTime

{
  "duration": {
    "start": "12:34",
    "end": "23:45"
  },
  // other fields here
}

And types ItemType and DurationType

ItemType defined a field "duration" like this

descriptor.Ignore(x=> x.EndTime);
descriptor.Ignore(x=> x.StartTime);
descriptor.Field("duration")
    .ResolveWith<TheResolver>(resolver => resolver.GetDuration(default!))
    .Type<DurationType>();
// other configurations here

The endpoint is marked with UseProjection and use EFCore data context.

When TheResolver.GetDuration() gets called it did not fetch the value for StartTime and EndTime from database. I think it's because the UseProjection tell it not to.

Is there any way to configure the Hot Chocolate to use projection on ignored fields StartTime and EndTime when the query requests duration field?

Specifying descriptor.Field(x => x.StartTime).IsProjected(true) does not work if the field specified as ignored.

UPDATE : Just found an issue on their github, looks like they're working on it (Issue #4192 - It's not possible to project an ignored property)

anuith
  • 659
  • 5
  • 16

2 Answers2

1

As a workaround for the issue in your particular case, you could make the selection with duration directly from queryable like:

dbContext.Items.Select(i => new ItemData { Duration = new Duration { Start = i.StartTime, End = i.End } })

And that IQueryable with the ready duration field to return further to [UseProjection] and whatever.

ademchenko
  • 585
  • 5
  • 18
  • Thank you @ademchenko, it took me this long to get back to this issue. I think your solution works. What I do is adding `[NotMapped]` property with calculations in the `ItemData` class directly. – anuith Sep 30 '22 at 12:44
0

@ademchenko's workaround works. But what I ended up with was to add a Duration property in the ItemData class with calculated getter/setter in a partial class to separate from original code. Inspired by that answer.

partial class ItemData
{
  public string StartTime { get; set; }
  public string EndTime { get; set; }

  // other fields here

}

partial class ItemData
{
  public Duration ItemDuration
  {
    get => new Duration { Start = this.StartTime, End = this.EndTime };
    set => (this.StartTime, this.EndTime) = (value.StartTime, value.EndTime);
  }
}

Use property name ItemDuration to distinguish the type name and property name in this example

anuith
  • 659
  • 5
  • 16
  • In your approach, you will probably lose the ability to add filters that map directly to the database, like items.Where(i => i.Duration.EndTime < DateTIme.Now). – ademchenko Sep 30 '22 at 17:12