Get List Example
Overview
This document demonstrates the complete Get List flow using the GetProductsForLookup feature from the EBusiness application. The flow starts with a GET request to the controller and uses Query projects instead of Handlers in the DomainHandler section for data retrieval. This is similar to Get Paged List but returns a simple IEnumerable<T>
without pagination.
Complete Flow Architecture
GET Request β Controller β Service β Query Handler β Database β Response
Detailed Flow Breakdown
1. GET Request
β
2. Controller (API Entry Point)
β
3. Service Layer (Business Orchestration)
β
4. Query Handler (Data Retrieval)
β
5. Database (Data Query)
β
6. AutoMapper (Data Transformation)
β
7. Response (Simple List)
Step-by-Step Implementation
1. API Controller - The Entry Point
File: ProductsController_GetProductsForLookup.cs
[HttpGet()]
[Route("GetProductsForLookup")]
[ProducesResponseType(typeof(IEnumerable<GetProductsForLookupDto>), 200)]
public async Task<IActionResult> GetProductsForLookup([FromQuery]GetProductsForLookupParams parameters)
{
return RunQueryListService<GetProductsForLookupParams, GetProductsForLookupDto>(
parameters, _processProductsService.GetProductsForLookup);
}
What Happens:
HTTP Method:
GET /api/Products/GetProductsForLookup
Input:
GetProductsForLookupParams
from query parametersAction: Calls the service layer to process the query
Response: HTTP 200 OK with
IEnumerable<GetProductsForLookupDto>
2. Service Layer - Business Orchestration
File: ProcessProductsService_GetProductsForLookup.cs
public IEnumerable<GetProductsForLookupDto> GetProductsForLookup(GetProductsForLookupParams @params)
{
return _flexHost.GetFlexiQuery<GetProductsForLookup>().AssignParameters(@params).Fetch();
}
What Happens:
Query Resolution: Gets the FlexiQuery instance for GetProductsForLookup
Parameter Assignment: Assigns query parameters to the query handler
Query Execution: Calls the Fetch() method to execute the query
Result: Returns simple list of products for lookup
3. Query Handler - Data Retrieval
File: GetProductsForLookup.cs
public class GetProductsForLookup : FlexiQueryEnumerableBridge<Product, GetProductsForLookupDto>
{
protected readonly ILogger<GetProductsForLookup> _logger;
protected GetProductsForLookupParams _params;
protected readonly RepoFactory _repoFactory;
public GetProductsForLookup(ILogger<GetProductsForLookup> logger, RepoFactory repoFactory)
{
_logger = logger;
_repoFactory = repoFactory;
}
public virtual GetProductsForLookup AssignParameters(GetProductsForLookupParams @params)
{
_params = @params;
return this;
}
public override IEnumerable<GetProductsForLookupDto> Fetch()
{
var result = Build<Product>().SelectTo<GetProductsForLookupDto>().ToList();
return result;
}
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
//Build Your Query Here
return query;
}
}
What Happens:
Parameter Assignment: Stores query parameters for use in query building
Query Building: Creates the database query with filtering
Data Projection: Uses AutoMapper to project to DTOs
Result Building: Creates the simple list output
4. Query Parameters - Input DTO
File: GetProductsForLookupParams.cs
public class GetProductsForLookupParams : DtoBridge
{
// Add custom filtering parameters here
public string SearchTerm { get; set; }
public string CategoryId { get; set; }
public bool? IsActive { get; set; }
public int? Limit { get; set; }
}
What Happens:
Custom Filters: Allows filtering by search term, category, active status
Limit Support: Optional limit for lookup results
Query Parameters: Automatically bound from URL query string
5. Output DTO - Data Transfer Object
File: GetProductsForLookupDto.cs
public partial class GetProductsForLookupDto : DtoBridge
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string CategoryName { get; set; }
public bool IsActive { get; set; }
}
What Happens:
Lookup Data: Contains essential fields for dropdown/lookup scenarios
Minimal Structure: Only includes necessary fields for selection
Performance: Lightweight DTO for fast loading
6. AutoMapper Configuration - Data Transformation
File: GetProductsForLookupMapperConfiguration.cs
public partial class GetProductsForLookupMapperConfiguration : FlexMapperProfile
{
public GetProductsForLookupMapperConfiguration() : base()
{
CreateMap<Product, GetProductsForLookupDto>()
.ForMember(d => d.CategoryName, opt => opt.MapFrom(s => s.Category.Name))
.ForMember(d => d.IsActive, opt => opt.MapFrom(s => !s.IsSoftDeleted));
}
}
What Happens:
Entity to DTO Mapping: Maps domain entities to DTOs
Custom Mappings: Handles complex property transformations
Lookup Optimization: Maps only necessary fields for lookup scenarios
Key Differences from Get Paged List
Get List vs Get Paged List Characteristics
Return Type
IEnumerable<T>
FlexiPagedList<T>
Pagination
β No pagination
β Built-in pagination
Use Case
Lookup/Dropdown
Data grids/tables
Performance
Fast for small datasets
Optimized for large datasets
Memory Usage
Lower (no pagination metadata)
Higher (includes pagination info)
Controller Method
RunQueryListService
RunQueryPagedService
Query Base
FlexiQueryEnumerableBridge
FlexiQueryPagedListBridge
Get List-Specific Features
Simple List: Returns basic
IEnumerable<T>
without paginationLookup Optimized: Designed for dropdown/lookup scenarios
Lightweight: Minimal data transfer for performance
No Pagination: All results returned in single response
Fast Loading: Optimized for quick data retrieval
Common Use Cases
Dropdown Lists: Populate dropdown controls
Lookup Tables: Search and select scenarios
Reference Data: Load reference data for forms
Auto-complete: Provide suggestions for input fields
Quick Filters: Fast filtering options
Flow Summary
Synchronous Flow (Data Retrieval)
GET Request β Controller receives request with query parameters
Service Processing β Business orchestration and query resolution
Query Handler β Database query building and execution
AutoMapper β Entity-to-DTO transformation
Response β HTTP 200 OK with simple list
No Asynchronous Flow
No Events: Query operations don't publish events
No Subscribers: No side effects or event processing
Immediate Response: Data is returned immediately
Query Building Patterns
Basic Query Building
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
// Add filtering logic here
if (!string.IsNullOrEmpty(_params.SearchTerm))
{
query = query.Where(p => p.Name.Contains(_params.SearchTerm) ||
p.Description.Contains(_params.SearchTerm));
}
if (!string.IsNullOrEmpty(_params.CategoryId))
{
query = query.Where(p => p.CategoryId == _params.CategoryId);
}
if (_params.IsActive.HasValue)
{
query = query.Where(p => p.IsSoftDeleted == !_params.IsActive.Value);
}
// Apply limit if specified
if (_params.Limit.HasValue)
{
query = query.Take(_params.Limit.Value);
}
return query;
}
Advanced Query Building
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
// Exclude soft deleted items
query = query.Where(p => !p.IsSoftDeleted);
// Search functionality
if (!string.IsNullOrEmpty(_params.SearchTerm))
{
var searchTerm = _params.SearchTerm.ToLower();
query = query.Where(p => p.Name.ToLower().Contains(searchTerm) ||
p.Description.ToLower().Contains(searchTerm) ||
p.Sku.ToLower().Contains(searchTerm));
}
// Category filtering
if (!string.IsNullOrEmpty(_params.CategoryId))
{
query = query.Where(p => p.CategoryId == _params.CategoryId);
}
// Active status filtering
if (_params.IsActive.HasValue)
{
query = query.Where(p => p.IsActive == _params.IsActive.Value);
}
// Price range filtering (if needed)
if (_params.MinPrice.HasValue)
{
query = query.Where(p => p.Price >= _params.MinPrice.Value);
}
if (_params.MaxPrice.HasValue)
{
query = query.Where(p => p.Price <= _params.MaxPrice.Value);
}
// Sorting for consistent results
query = query.OrderBy(p => p.Name);
// Apply limit for performance
if (_params.Limit.HasValue)
{
query = query.Take(_params.Limit.Value);
}
else
{
// Default limit for lookup scenarios
query = query.Take(100);
}
return query;
}
Performance Considerations
Optimization Strategies
Limit Results: Always apply reasonable limits for lookup scenarios
Selective Fields: Only return necessary fields in DTO
Indexing: Ensure proper database indexes on filter fields
Caching: Consider caching for frequently accessed lookup data
Lazy Loading: Use lazy loading for related entities when appropriate
When to Use Get List vs Get Paged List
Dropdown Population
β Yes
β No
Lookup Tables
β Yes
β No
Auto-complete
β Yes
β No
Data Grids
β No
β Yes
Large Datasets
β No
β Yes
Admin Interfaces
β No
β Yes
Reporting
β No
β Yes
Key Benefits
Performance: Fast loading for small datasets
Simplicity: Simple list without pagination complexity
Lookup Optimized: Perfect for dropdown/lookup scenarios
Lightweight: Minimal data transfer
Type Safety: Strongly typed DTOs and parameters
AutoMapper: Automatic entity-to-DTO mapping
No Side Effects: Read-only operations
Testable: Each component can be tested independently
Maintainable: Clear separation of concerns
This GetProductsForLookup example demonstrates how FlexBase enables clean, maintainable, and scalable list operations optimized for lookup and dropdown scenarios! π
Last updated