.SelectDynamic<T>(fields)
Projects only the specified fields using System.Linq.Dynamic.Core's string-based Select, returning a non-generic dynamic IQueryable. Dotted navigation paths are projected as nested dynamic objects that mirror the navigation hierarchy, including through collection properties.
Signature
public static IQueryable SelectDynamic<T>(this IQueryable<T> query, List<string> fields)
where T : class| Parameter | Type | Description |
|---|---|---|
query | IQueryable<T> | Source query to project |
fields | List<string> | Property paths to include |
Projection rules
| Path style | Behaviour | Example input | Dynamic result |
|---|---|---|---|
| Non-dotted scalar | Projected as-is | "Name" | Name: "Laptop" |
| Non-dotted object | Projected as-is (whole object) | "Category" | Category: { Id: 5, Name: "Electronics" } |
| Non-dotted collection | Projected as-is (whole collection) | "Brands" | Brands: [{ Id: 1, … }] |
| Dotted through reference navigation | Nested object per segment | "Category.Name" | Category: { Name: "Electronics" } |
| Dotted through collection navigation | Select lambda per collection segment | "Category.Vendors.Id" | Category: { Vendors: [{ Id: 1 }] } |
| Multi-level dotted (reference + collection) | Mixed nesting and Select lambdas | "Category.Vendors.Product.Name" | Category: { Vendors: [{ Product: { Name: "…" } }] } |
| Nested collections (any depth) | Select lambda at each collection level | "A.ListB.ListC.Name" | A: { ListB: [{ ListC: [{ Name: "…" }] }] } |
| Multi-level dotted (deep reference) | Deeply nested objects | "Category.SubCategory.Name" | Category: { SubCategory: { Name: "Laptops" } } |
Merging rule
Multiple dotted fields sharing the same root segment are merged into the same nested object:
["Category.Name", "Category.Id"]produces Category: { Name: "...", Id: 5 }.
Whole-vs-sub-field precedence
"Category") and sub-field paths sharing the same root segment (e.g., "Category.Name") are requested, the sub-field projection takes precedence and the whole-navigation entry is silently dropped.Validations
queryandfieldscannot be null.fieldsmust have at least one entry.- Every field must exist on
T(case-insensitive, auto-normalized).
.Select<T>, this method does not require a parameterless constructor on T.Returns
IQueryable — a dynamic projected query where each element is an anonymous object.
Examples
Direct scalars.
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Name", "Price" });{ "Id": 7, "Name": "Laptop Pro", "Price": 1299.99 }Dotted path through reference navigation (nested object).
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Name", "Price", "Category.Name" });{ "Id": 7, "Name": "Laptop Pro", "Price": 1299.99, "Category": { "Name": "Electronics" } }Dotted path through collection navigation (Select lambda).
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Name", "Category.Vendors.Id" });{ "Id": 7, "Name": "Laptop Pro", "Category": { "Vendors": [{ "Id": 3 }, { "Id": 7 }] } }Multi-level dotted (reference → collection → reference).
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Category.Vendors.Product.Name" });{ "Id": 7, "Category": { "Vendors": [{ "Product": { "Name": "Laptop Pro" } }] } }Merged sub-fields.
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Category.Name", "Category.Id" });{ "Id": 7, "Category": { "Name": "Electronics", "Id": 5 } }Whole navigation object.
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Name", "Category" });{ "Id": 7, "Name": "Laptop Pro", "Category": { "Id": 5, "Name": "Electronics" } }Whole collection.
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Name", "OrderItems" });{ "Id": 7, "Name": "Laptop Pro", "OrderItems": [ { "Id": 1, "Quantity": 2 } ] }Deep reference nesting.
var dynQuery = dbContext.Products
.SelectDynamic(new List<string> { "Id", "Category.SubCategory.Name" });{ "Id": 7, "Category": { "SubCategory": { "Name": "Laptops" } } }See also
.Select<T>— strongly-typed variant returningIQueryable<T>..FilterDynamic<T>— applywhere → order → page → dynamic select.- JSON Cookbook: SelectDynamic.