You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -729,7 +790,6 @@ public class ResultsRepository(
729
790
.SelectMany(r => r.RaceResults!.Where(
730
791
finish => finish.Position <= 10)
731
792
)
732
-
// ✨ Notice how everything is fully typed downstack
733
793
.Select(finish => new {
734
794
RunnerName = finish.Runner.Name,
735
795
RaceName = finish.Race.Name,
@@ -773,7 +833,9 @@ public class AppController(
773
833
public string Get() => "Hello, World!";
774
834
775
835
[HttpGet("/top10/{email}")]
776
-
public async Task<List<RunnerRaceResult>> GetTop10FinishesByRunner(string email) {
836
+
public async Task<
837
+
List<RunnerRaceResult>
838
+
> GetTop10FinishesByRunner(string email) {
777
839
var results = await resultsRepository.Top10FinishesByRunner(email);
778
840
return [.. results];
779
841
}
@@ -783,15 +845,51 @@ public class AppController(
783
845
</template>
784
846
</CodeSplitter>
785
847
848
+
::: info An important distinction
849
+
On the TypeScript side, the `.map` projection takes place on the *client side* after the result has been returned. On the .NET side, the projection and aliasing takes place *on the database server*; the first `.Select()` expression is transformed into a SQL `SELECT field AS alias, ...` whereas the second `Select()` materializes it into the record.
850
+
:::
851
+
786
852
## Hoisting Navigations
787
853
788
854
EF Core will attempt to persist the entire object tree if you round-trip the entity. To prevent this -- for example, we only want to round-trip the runner -- we can use a simple technique here to split out the navigation collections from the results:
789
855
790
856
<CodeSplitter>
791
857
<template #left>
792
858
793
-
```ts
794
-
// 🚧 WIP
859
+
```ts{18,19}
860
+
// 📄 results-repository.ts: Retrieve a runner and her results
861
+
async runnerResults(email: string) { // [!code warning] Only a shape here, not a type
@@ -829,6 +927,8 @@ public async Task<RunnerResults> GetRunnerResults(string email) {
829
927
830
928
Remember how we used `[JsonIgnore]` in our model? This means that at serialization at the boundary, `Runner.Races` and `Runner.RaceResults` will automatically be stripped out (nice)! So to keep them in the output JSON, we need to "hoist" them up into a "DTO" record.
831
929
930
+
On the Prisma side, it's not so easy. We'll either have to do a deeper selection or explicitly delete fields off of our objects to ensure they do not round trip. It's possible to use [lodash's `omit`](https://www.geeksforgeeks.org/lodash-_-omit-method/) or JavaScript `delete` to remove the navigations manually.
931
+
832
932
::: tip
833
933
This is an extremely useful pattern and should generally be used for all navigation properties as it will allow round-tripping the entity for updates without passing the navigations along.
0 commit comments