Skip to content

Combine AutoInclude with Filtered Include #30883

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
luissalgadofreire opened this issue May 12, 2023 · 2 comments
Open

Combine AutoInclude with Filtered Include #30883

luissalgadofreire opened this issue May 12, 2023 · 2 comments

Comments

@luissalgadofreire
Copy link

luissalgadofreire commented May 12, 2023

I am looking for a solution to something like what was mentioned in:

#21991 (comment)

Given we have NavigationBuilder, it would be better to put them on NavigationBuilder.

modelBuilder.Entity<Student>().Navigation(e => e.Courses).HasIncludeFilter(e => e.Where(course => course.Difficulty >10));

@AndriySvyryd - Do we need a generic Navigation Builder now?

I noticed however, that Navigation() together with AutoInclude() does not seem to support filtered include. Is there any alternative way to achieve this in EntityTypeBuilder?

I was looking to use that with generics to get a translated entry or a fallback. I first tried:

public override void Configure(EntityTypeBuilder<TTranslatable> builder) {
    builder.HasMany(p => p.Translations)
      .WithOne(c => c.Parent)
      .HasForeignKey(c => c.ParentId)
      .IsRequired()
      .OnDelete(DeleteBehavior.Cascade);
  
    builder.Navigation(
       p => p.Translations.Where(t => t.Language == requestLanguage || t.IsDefaultLanguage == true)
         .OrderBy(t => t.IsDefaultLanguage)
         .Take(1)
       )
       .AutoInclude();

    base.Configure(builder);
  }

But, though it compiles, it throws an exception at runtime, complaining that the Where|OrderBy|Take clause should be removed: only a simple p => p.Translations should be referenced.

Is there any way to achieve something like this without having to repeat the filtered include in every individual query?

@ajcvickers
Copy link
Contributor

@luissalgadofreire Wouldn't a global query filter be more appropriate here?

@luissalgadofreire
Copy link
Author

luissalgadofreire commented May 17, 2023

Thanks for the attention, @ajcvickers. I tried a global query filter on Translation as an alternative. But, as far as I could find, global query filters do not support Where, OrderBy and Take, unlike filtered include.

If I just wanted a simple filter as in t => t.Language == requestLanguage to get the requested language, it would be ok.

But if I want to get a fallback based on the record marked with IsDefaultLanguage, I would need the OrderBy and Take.

Filtered includes supports that. Global query filters don't.

Unfortunately, the more powerful syntax of filtered include does not work with AutoInclude. So, we can use it in individual queries but cannot generalize it with generics, like I was trying to do.

If filtered include now supports a syntax like:

p => p.Translations.Where(t => t.Language == requestLanguage || t.IsDefaultLanguage == true)
         .OrderBy(t => t.IsDefaultLanguage)
         .Take(1)

It would be interesting and intuitive for it to be supported inside Navigation() as in above or with a HasIncludeFilter as suggested in #21991. It would make such powerful syntax available in individual queries but also in a place that allows for more DRY code in more generic use cases.

Of course, in my case, an alternative would be for global query filters to support Where, OrderBy, and Take, instead of just a simple filter expression like t => t.Language == requestLanguage.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants