Skip to content

Commit 64b9787

Browse files
authored
docs: add Nested SelectExpr documentation for reusable DTOs (#225)
* docs: add Nested SelectExpr documentation for reusable DTOs * docs: update Nested SelectExpr documentation with important notes and usage requirements * upd * Fix GitHub Issue link in nested-selectexpr.md
1 parent 755698c commit 64b9787

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ For more usage patterns and examples, see the [Usage Patterns Guide](./docs/libr
241241
### Customization
242242

243243
* **[Local Variable Capture](./docs/library/local-variable-capture.md)** - Using local variables in SelectExpr
244+
* **[Nested SelectExpr](./docs/library/nested-selectexpr.md) (beta)** - Using nested SelectExpr for reusable DTOs
244245
* **[Array Nullability Removal](./docs/library/array-nullability.md)** - Automatic null handling for collections
245246
* **[Partial Classes](./docs/library/partial-classes.md)** - Extending generated DTOs
246247
* **[Nested DTO Naming](./docs/library/nested-dto-naming.md)** - Customizing nested DTO names

docs/library/nested-selectexpr.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Nested SelectExpr (Beta)
2+
3+
You can use `SelectExpr` inside another `SelectExpr` to explicitly control the DTO class generation for nested collections.
4+
This allows you to create reusable DTOs for nested entities instead of auto-generated DTOs in hash namespaces.
5+
6+
## Important Notes
7+
8+
### Beta Feature Warning
9+
10+
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.
11+
12+
### .NET 9+ Recommended
13+
14+
This feature is **recommended for .NET 9 or later**.
15+
In older .NET versions, type inference may fail for unknown reasons.
16+
See [GitHub Issue #211](https://github.com/arika0093/linqraft/issues/211) for details.
17+
18+
### Empty Partial Class Declarations Required
19+
20+
To ensure DTOs are generated in the correct location, you **must** declare empty partial class definitions for all explicit DTO types:
21+
22+
```csharp
23+
public class MyService
24+
{
25+
public void GetOrders(IQueryable<Order> query)
26+
{
27+
var result = query
28+
.SelectExpr<Order, OrderDto>(o => new
29+
{
30+
o.Id,
31+
Items = o.OrderItems.SelectExpr<OrderItem, OrderItemDto>(i => new
32+
{
33+
i.ProductName,
34+
}),
35+
});
36+
}
37+
38+
// Empty partial class definitions - REQUIRED
39+
internal partial class OrderDto;
40+
internal partial class OrderItemDto;
41+
}
42+
```
43+
44+
**Why is this necessary?**
45+
46+
The source generator determines where to generate DTOs based on where the empty partial class is declared. Without these declarations:
47+
- The generator might place DTOs in the wrong namespace
48+
- DTO generation might fail
49+
- The generated code might not compile
50+
51+
## Basic Usage
52+
53+
```csharp
54+
var result = query
55+
.SelectExpr<Order, OrderDto>(o => new
56+
{
57+
o.Id,
58+
o.CustomerName,
59+
// Using SelectExpr - ItemDto is generated in your namespace
60+
Items = o.OrderItems.SelectExpr<OrderItem, OrderItemDto>(i => new
61+
{
62+
i.ProductName,
63+
i.Quantity,
64+
}),
65+
});
66+
67+
// Required partial class declarations
68+
internal partial class OrderDto;
69+
internal partial class OrderItemDto;
70+
```
71+
72+
**Generated DTOs:**
73+
```csharp
74+
namespace MyProject
75+
{
76+
public partial class OrderDto
77+
{
78+
public required int Id { get; set; }
79+
public required string CustomerName { get; set; }
80+
public required IEnumerable<OrderItemDto> Items { get; set; }
81+
}
82+
83+
// This DTO is directly accessible and reusable
84+
public partial class OrderItemDto
85+
{
86+
public required string ProductName { get; set; }
87+
public required int Quantity { get; set; }
88+
}
89+
}
90+
```
91+
92+
## Multiple Nesting Levels
93+
94+
You can nest `SelectExpr` calls multiple levels deep:
95+
96+
```csharp
97+
var result = query
98+
.SelectExpr<Entity, EntityDto>(x => new
99+
{
100+
x.Id,
101+
x.Name,
102+
Items = x.Items.SelectExpr<Item, ItemDto>(i => new
103+
{
104+
i.Id,
105+
i.Title,
106+
SubItems = i.SubItems.SelectExpr<SubItem, SubItemDto>(si => new
107+
{
108+
si.Id,
109+
si.Value,
110+
}),
111+
}),
112+
})
113+
.ToList();
114+
115+
// Declare all DTO types
116+
internal partial class EntityDto;
117+
internal partial class ItemDto;
118+
internal partial class SubItemDto;
119+
```
120+
121+
## Mixing Select and SelectExpr
122+
123+
You can mix regular `Select` and `SelectExpr` within the same query:
124+
125+
```csharp
126+
var result = query
127+
.SelectExpr<Entity, EntityDto>(x => new
128+
{
129+
x.Id,
130+
// Reusable DTO - generated in your namespace
131+
Items = x.Items.SelectExpr<Item, ItemDto>(i => new
132+
{
133+
i.Id,
134+
// Auto-generated DTO in hash namespace
135+
SubItems = i.SubItems.Select(si => new { si.Value }),
136+
}),
137+
});
138+
139+
internal partial class EntityDto;
140+
internal partial class ItemDto;
141+
// No need to declare SubItemDto - it's auto-generated
142+
```
143+
144+
## When to Use Nested SelectExpr
145+
146+
**Use nested `SelectExpr` when:**
147+
* You need to reuse nested DTOs across multiple queries
148+
* You want full control over nested DTO naming
149+
* You need to extend nested DTOs with partial classes
150+
* You want to reference nested DTOs in your API documentation
151+
152+
**Use regular `Select` when:**
153+
* The nested DTO is used only once
154+
* You don't need to reference the nested DTO type
155+
* You prefer simpler, less verbose code
156+
157+
## Comparison
158+
159+
| Feature | Regular Select | Nested SelectExpr |
160+
|---------|---------------|-------------------|
161+
| DTO Location | `LinqraftGenerated_HASH` namespace | Your namespace |
162+
| Reusability | No | Yes |
163+
| Declaration Required | No | Yes (empty partial class) |
164+
| .NET Version | Any | .NET 9+ recommended |
165+
166+
## See Also
167+
168+
* [Usage Patterns](usage-patterns.md) - Overview of all SelectExpr patterns
169+
* [Nested DTO Naming](nested-dto-naming.md) - Configure nested DTO naming strategy
170+
* [Partial Classes](partial-classes.md) - Extend generated DTOs

0 commit comments

Comments
 (0)