-
-
Notifications
You must be signed in to change notification settings - Fork 0
docs: add Nested SelectExpr documentation for reusable DTOs #225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
449665c
docs: add Nested SelectExpr documentation for reusable DTOs
arika0093 3fddaf5
docs: update Nested SelectExpr documentation with important notes and…
arika0093 782d2db
upd
arika0093 224d24f
Fix GitHub Issue link in nested-selectexpr.md
arika0093 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| # Nested SelectExpr (Beta) | ||
|
|
||
| You can use `SelectExpr` inside another `SelectExpr` to explicitly control the DTO class generation for nested collections. This allows you to create reusable DTOs for nested entities instead of auto-generated DTOs in hash namespaces. | ||
|
|
||
| ## Important Notes | ||
|
|
||
| ### Beta Feature Warning | ||
|
|
||
| This feature is currently in **beta** (available since v0.6.2). While it works correctly, the API and behavior may change in future versions. Please report any issues on GitHub. | ||
|
|
||
| ### .NET 9+ Recommended | ||
|
|
||
| This feature is **strongly recommended for .NET 9 or later**. In older .NET versions, type inference may fail for unknown reasons. See [GitHub Issue #211](https://github.com/your-org/linqraft/issues/211) for details. | ||
|
|
||
| If you must use this feature on older .NET versions: | ||
| * Test thoroughly | ||
| * Watch for type inference errors | ||
| * Consider upgrading to .NET 9+ if possible | ||
|
|
||
| ### Required: Empty Partial Class Declarations | ||
|
|
||
| To ensure DTOs are generated in the correct location, you **must** declare empty partial class definitions for all explicit DTO types: | ||
|
|
||
| ```csharp | ||
| public class MyService | ||
| { | ||
| public void GetOrders(IQueryable<Order> query) | ||
| { | ||
| var result = query | ||
| .SelectExpr<Order, OrderDto>(o => new | ||
| { | ||
| o.Id, | ||
| Items = o.OrderItems.SelectExpr<OrderItem, OrderItemDto>(i => new | ||
| { | ||
| i.ProductName, | ||
| }), | ||
| }); | ||
| } | ||
|
|
||
| // Empty partial class definitions - REQUIRED | ||
| internal partial class OrderDto; | ||
| internal partial class OrderItemDto; | ||
| } | ||
| ``` | ||
|
|
||
| **Why is this necessary?** | ||
|
|
||
| The source generator determines where to generate DTOs based on where the empty partial class is declared. Without these declarations: | ||
| - The generator might place DTOs in the wrong namespace | ||
| - DTO generation might fail | ||
| - The generated code might not compile | ||
|
|
||
| **Requirements:** | ||
| 1. Always declare empty partial class definitions for all explicit DTO types | ||
| 2. Place the partial class definitions in the same scope as the `SelectExpr` call | ||
| 3. Use the correct access modifier (`public`, `internal`, etc.) | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| ```csharp | ||
| var result = query | ||
| .SelectExpr<Order, OrderDto>(o => new | ||
| { | ||
| o.Id, | ||
| o.CustomerName, | ||
| // Using SelectExpr - ItemDto is generated in your namespace | ||
| Items = o.OrderItems.SelectExpr<OrderItem, OrderItemDto>(i => new | ||
| { | ||
| i.ProductName, | ||
| i.Quantity, | ||
| }), | ||
| }); | ||
|
|
||
| // Required partial class declarations | ||
| internal partial class OrderDto; | ||
| internal partial class OrderItemDto; | ||
| ``` | ||
|
|
||
| **Generated DTOs:** | ||
| ```csharp | ||
| namespace MyProject | ||
| { | ||
| public partial class OrderDto | ||
| { | ||
| public required int Id { get; set; } | ||
| public required string CustomerName { get; set; } | ||
| public required IEnumerable<OrderItemDto> Items { get; set; } | ||
| } | ||
|
|
||
| // This DTO is directly accessible and reusable | ||
| public partial class OrderItemDto | ||
| { | ||
| public required string ProductName { get; set; } | ||
| public required int Quantity { get; set; } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Multiple Nesting Levels | ||
|
|
||
| You can nest `SelectExpr` calls multiple levels deep: | ||
|
|
||
| ```csharp | ||
| var result = query | ||
| .SelectExpr<Entity, EntityDto>(x => new | ||
| { | ||
| x.Id, | ||
| x.Name, | ||
| Items = x.Items.SelectExpr<Item, ItemDto>(i => new | ||
| { | ||
| i.Id, | ||
| i.Title, | ||
| SubItems = i.SubItems.SelectExpr<SubItem, SubItemDto>(si => new | ||
| { | ||
| si.Id, | ||
| si.Value, | ||
| }), | ||
| }), | ||
| }) | ||
| .ToList(); | ||
|
|
||
| // Declare all DTO types | ||
| internal partial class EntityDto; | ||
| internal partial class ItemDto; | ||
| internal partial class SubItemDto; | ||
| ``` | ||
|
|
||
| ## Mixing Select and SelectExpr | ||
|
|
||
| You can mix regular `Select` and `SelectExpr` within the same query: | ||
|
|
||
| ```csharp | ||
| var result = query | ||
| .SelectExpr<Entity, EntityDto>(x => new | ||
| { | ||
| x.Id, | ||
| // Reusable DTO - generated in your namespace | ||
| Items = x.Items.SelectExpr<Item, ItemDto>(i => new | ||
| { | ||
| i.Id, | ||
| // Auto-generated DTO in hash namespace | ||
| SubItems = i.SubItems.Select(si => new { si.Value }), | ||
| }), | ||
| }); | ||
|
|
||
| internal partial class EntityDto; | ||
| internal partial class ItemDto; | ||
| // No need to declare SubItemDto - it's auto-generated | ||
| ``` | ||
|
|
||
| ## Collection Types | ||
|
|
||
| Nested `SelectExpr` works with various collection types: | ||
|
|
||
| ```csharp | ||
| var result = query | ||
| .SelectExpr<Entity, EntityDto>(x => new | ||
| { | ||
| // IEnumerable (default) | ||
| ItemsEnumerable = x.Items.SelectExpr<Item, ItemDtoEnumerable>(i => new { i.Id }), | ||
|
|
||
| // List | ||
| ItemsList = x.Items.SelectExpr<Item, ItemDtoList>(i => new { i.Id }).ToList(), | ||
|
|
||
| // Array | ||
| ItemsArray = x.Items.SelectExpr<Item, ItemDtoArray>(i => new { i.Id }).ToArray(), | ||
| }); | ||
|
|
||
| internal partial class EntityDto; | ||
| internal partial class ItemDtoEnumerable; | ||
| internal partial class ItemDtoList; | ||
| internal partial class ItemDtoArray; | ||
| ``` | ||
|
|
||
| ## When to Use Nested SelectExpr | ||
|
|
||
| **Use nested `SelectExpr` when:** | ||
| * You need to reuse nested DTOs across multiple queries | ||
| * You want full control over nested DTO naming | ||
| * You need to extend nested DTOs with partial classes | ||
| * You want to reference nested DTOs in your API documentation | ||
|
|
||
| **Use regular `Select` when:** | ||
| * The nested DTO is used only once | ||
| * You don't need to reference the nested DTO type | ||
| * You prefer simpler, less verbose code | ||
|
|
||
| ## Comparison | ||
|
|
||
| | Feature | Regular Select | Nested SelectExpr | | ||
| |---------|---------------|-------------------| | ||
| | DTO Location | `LinqraftGenerated_HASH` namespace | Your namespace | | ||
| | Reusability | No | Yes | | ||
| | Declaration Required | No | Yes (empty partial class) | | ||
| | .NET Version | Any | .NET 9+ recommended | | ||
|
|
||
| ## See Also | ||
|
|
||
| * [Usage Patterns](usage-patterns.md) - Overview of all SelectExpr patterns | ||
| * [Nested DTO Naming](nested-dto-naming.md) - Configure nested DTO naming strategy | ||
| * [Partial Classes](partial-classes.md) - Extend generated DTOs | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.