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 parameters

  • Action: 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

Aspect
Get List
Get Paged List

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

  1. Simple List: Returns basic IEnumerable<T> without pagination

  2. Lookup Optimized: Designed for dropdown/lookup scenarios

  3. Lightweight: Minimal data transfer for performance

  4. No Pagination: All results returned in single response

  5. 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)

  1. GET Request β†’ Controller receives request with query parameters

  2. Service Processing β†’ Business orchestration and query resolution

  3. Query Handler β†’ Database query building and execution

  4. AutoMapper β†’ Entity-to-DTO transformation

  5. 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

  1. Limit Results: Always apply reasonable limits for lookup scenarios

  2. Selective Fields: Only return necessary fields in DTO

  3. Indexing: Ensure proper database indexes on filter fields

  4. Caching: Consider caching for frequently accessed lookup data

  5. Lazy Loading: Use lazy loading for related entities when appropriate

When to Use Get List vs Get Paged List

Scenario
Use Get List
Use 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