> For the complete documentation index, see [llms.txt](https://docs.flexbase.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flexbase.in/solution-structure/getting-started/features/crud/get-list-example.md).

# 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`

```csharp
[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`

```csharp
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`

```csharp
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`

```csharp
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`

```csharp
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`

```csharp
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**

```csharp
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**

```csharp
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!** 🚀
