# Insert Example

## Overview

This document demonstrates the complete **Insert flow** using the **AddOrder** feature from the EBusiness application. The flow starts with a POST request to the controller and ends with event publishing and subscriber processing.

## Complete Flow Architecture

```
POST Request → Controller → Service → PreBus Plugins → Command Handler → Domain Model → Database → Event Publishing → Subscribers
```

### **Detailed Flow Breakdown**

```
1. POST Request
   ↓
2. Controller (API Entry Point)
   ↓
3. Service Layer (Business Orchestration)
   ↓
4. PreBus Processing (Validation Pipeline)
   ├── AddOrderSequence (Plugin Registration)
   ├── AddOrderDataPacket (Validation Context)
   └── ValidateCustomer Plugin (Business Rules)
   ↓
5. Command Handler (Data Processing)
   ↓
6. Domain Model (Business Logic)
   ↓
7. Database (Data Persistence)
   ↓
8. Event Publishing (Asynchronous Processing)
   ↓
9. Subscribers (Side Effects)
```

## Step-by-Step Implementation

### 1. **API Controller** - The Entry Point

**File**: `OrdersController_AddOrder.cs`

```csharp
[HttpPost]
[Route("AddOrder")]
[ProducesResponseType(typeof(BadRequestResult), 400)]
[ProducesResponseType(typeof(string), 201)]
public async Task<IActionResult> AddOrder([FromBody]AddOrderDto dto)
{
    return await RunService(201, dto, _processOrdersService.AddOrder);
}
```

**What Happens:**

* **HTTP Method**: `POST /api/Orders/AddOrder`
* **Input**: `AddOrderDto` from request body
* **Action**: Calls the service layer to process the order
* **Response**: HTTP 201 Created with order ID

### 2. **Service Layer** - Business Orchestration

**File**: `ProcessOrdersService_AddOrder.cs`

```csharp
public async Task<CommandResult> AddOrder(AddOrderDto dto)
{
    var packet = await ProcessBusinessRuleSequence<AddOrderDataPacket, AddOrderSequence, AddOrderDto, FlexAppContextBridge>(dto);

    if (packet.HasError)
    {
        return new CommandResult(Status.Failed, packet.Errors());
    }
    else
    {
        dto.SetGeneratedId(_pkGenerator.GenerateKey());
        AddOrderCommand cmd = new AddOrderCommand
        {
             Dto = dto,
        };

        await ProcessCommand(cmd);

        CommandResult cmdResult = new CommandResult(Status.Success);

        AddOrderResultModel outputResult = new AddOrderResultModel();
        outputResult.Id = dto.GetGeneratedId();
        cmdResult.result = outputResult;

        return cmdResult;
    }
}
```

**What Happens:**

* **PreBus Processing**: Executes business rule sequences (plugins)
* **Validation**: Processes business rule sequences
* **ID Generation**: Generates unique order ID
* **Command Creation**: Creates `AddOrderCommand` with DTO
* **Command Processing**: Calls the command handler
* **Result**: Returns success with generated order ID

### 2.1. **PreBus Business Rule Sequence** - Validation Pipeline

**File**: `AddOrderSequence.cs`

```csharp
public class AddOrderSequence : FlexiBusinessRuleSequenceBase<AddOrderDataPacket>
{
    public AddOrderSequence()
    {
        this.Add<ValidateCustomer>(); 
    }
}
```

**What Happens:**

* **Plugin Registration**: Registers validation plugins in execution order
* **Sequential Processing**: Executes plugins one by one
* **Error Collection**: Collects validation errors from all plugins
* **Early Exit**: Stops processing if any plugin fails

### 2.2. **PreBus Data Packet** - Validation Context

**File**: `AddOrderDataPacket.cs`

```csharp
public partial class AddOrderDataPacket : FlexiFlowDataPacketWithDtoBridge<AddOrderDto, FlexAppContextBridge>
{
    protected readonly ILogger<AddOrderDataPacket> _logger;

    public AddOrderDataPacket(ILogger<AddOrderDataPacket> logger)
    {
        _logger = logger;
    }

    #region "Properties
    //Models and other properties goes here
    #endregion
}
```

**What Happens:**

* **Context Container**: Holds DTO and application context
* **Error Collection**: Collects validation errors from plugins
* **Data Sharing**: Allows plugins to share data during validation
* **Logging**: Provides logging capabilities for plugins

### 2.3. **PreBus Validation Plugin** - Business Rules

**File**: `ValidateCustomer.cs`

```csharp
public partial class ValidateCustomer : FlexiBusinessRuleBase, IFlexiBusinessRule<AddOrderDataPacket>
{
    public override string Id { get; set; } = "3a1cd0401f931dd4a01587e229b720dc";
    public override string FriendlyName { get; set; } = "ValidateCustomer";

    protected readonly ILogger<ValidateCustomer> _logger;
    protected readonly RepoFactory _repoFactory;

    public ValidateCustomer(ILogger<ValidateCustomer> logger, RepoFactory repoFactory)
    {
        _logger = logger;
        _repoFactory = repoFactory;
    }

    public virtual async Task Validate(AddOrderDataPacket packet)
    {
        //Uncomment the below line if validating against a db data using your repo
        //_repoFactory.Init(packet.Dto);

        //If any validation fails, uncomment and use the below line of code to add error to the packet
        //packet.AddError("key", "ErrorMessage");

        await Task.CompletedTask; //If you have any await in the validation, remove this line
    }
}
```

**What Happens:**

* **Business Rule Validation**: Implements specific validation logic
* **Database Access**: Can access repository for data validation
* **Error Reporting**: Adds errors to the data packet if validation fails
* **Async Support**: Supports asynchronous validation operations
* **Dependency Injection**: Receives logger and repository factory

### 2.4. **PreBus Plugin Benefits**

* **Modular Validation**: Each plugin handles one validation concern
* **Reusable Rules**: Plugins can be reused across different features
* **Testable**: Each plugin can be unit tested independently
* **Configurable**: Plugins can be enabled/disabled per feature
* **Extensible**: Easy to add new validation rules
* **Ordered Execution**: Plugins execute in defined sequence

### 3. **Command Handler** - Data Processing

**File**: `AddOrderHandler.cs`

```csharp
public virtual async Task Execute(AddOrderCommand cmd, IFlexServiceBusContext serviceBusContext)
{
    _flexAppContext = cmd.Dto.GetAppContext();
    _repoFactory.Init(cmd.Dto);

    _model = _flexHost.GetDomainModel<Order>().AddOrder(cmd);
    _repoFactory.GetRepo().InsertOrUpdate(_model);
    int records = await _repoFactory.GetRepo().SaveAsync();
    
    if (records > 0)
    {
        _logger.LogDebug("{Entity} with {EntityId} inserted into Database: ", typeof(Order).Name, _model.Id);
    }
    else
    {
        _logger.LogWarning("No records inserted for {Entity} with {EntityId}", typeof(Order).Name, _model.Id);
    }
    
    await this.Fire(EventCondition, serviceBusContext);
}
```

**What Happens:**

* **Context Setup**: Initializes application context and repository
* **Domain Logic**: Calls domain model to process business rules
* **Database Save**: Inserts/updates the order in database
* **Logging**: Logs success/failure of database operation
* **Event Publishing**: Fires events for subscribers

### 4. **Domain Model** - Business Logic

**File**: `Order/AddOrder.cs`

```csharp
public virtual Order AddOrder(AddOrderCommand cmd)
{
    Guard.AgainstNull("Order command cannot be empty", cmd);

    this.Convert(cmd.Dto);
    this.CreatedBy = cmd.Dto.GetAppContext()?.UserId;
    this.LastModifiedBy = cmd.Dto.GetAppContext()?.UserId;

    this.SetAdded(cmd.Dto.GetGeneratedId());

    //Set your appropriate SetAdded for the inner object here
    this.OrderState = new OrderIsCreated().SetTFlexId(this.Id).SetStateChangedBy("");
    this.TotalAmount = this.OrderItems.Select(s => s.SellingPrice).Sum();
    this.TotalQty = this.OrderItems.Select(s => s.Qty).Sum();

    this.OrderItems.SetAddedOrModified();

    return this;
}
```

**What Happens:**

* **Validation**: Guards against null commands
* **Data Mapping**: Converts DTO to domain model
* **Audit Fields**: Sets created/modified by user
* **ID Assignment**: Sets the generated ID
* **Business Rules**: Calculates totals, sets order state
* **Child Objects**: Processes order items

### 5. **NServiceBus Handler** - Message Processing

**File**: `AddOrderNsbHandler.cs`

```csharp
public class AddOrderNsbHandler : NsbCommandHandler<AddOrderCommand>
{
    readonly ILogger<AddOrderNsbHandler> _logger;
    readonly IFlexHost _flexHost;
    readonly IAddOrderHandler _handler;

    public AddOrderNsbHandler(ILogger<AddOrderNsbHandler> logger, IFlexHost flexHost, IAddOrderHandler handler)
    {
        _logger = logger;
        _flexHost = flexHost;
        _handler = handler;
    }

    public override async Task Handle(AddOrderCommand message, IMessageHandlerContext context)
    {
        _logger.LogTrace($"Executing {nameof(AddOrderNsbHandler)}");

        await _handler.Execute(message, new NsbHandlerContextBridge(context));
    }
}
```

**What Happens:**

* **Message Reception**: Receives `AddOrderCommand` from message bus
* **Logging**: Logs handler execution
* **Delegation**: Calls the actual command handler
* **Context Bridge**: Converts NServiceBus context to FlexBase context

### 6. **Event Publishing** - Asynchronous Processing

**Event**: `OrderAddedEvent`

```csharp
public class OrderAddedEvent : FlexEventBridge<FlexAppContextBridge>
{
    // Event data is automatically populated by FlexBase
}
```

**What Happens:**

* **Event Creation**: FlexBase creates event with order data
* **Message Bus**: Event is published to message bus
* **Subscriber Notification**: All subscribers are notified

### 7. **Event Subscribers** - Side Effects

**File**: `NotifyAccountsOnOrderAdded.cs`

```csharp
public partial class NotifyAccountsOnOrderAdded : INotifyAccountsOnOrderAdded
{
    protected readonly ILogger<NotifyAccountsOnOrderAdded> _logger;
    protected string EventCondition = "";

    public NotifyAccountsOnOrderAdded(ILogger<NotifyAccountsOnOrderAdded> logger)
    {
        _logger = logger;
    }

    public virtual async Task Execute(OrderAddedEvent @event, IFlexServiceBusContext serviceBusContext)
    {
        _flexAppContext = @event.AppContext;

        //TODO: Write your business logic here:
        // - Send confirmation email
        // - Update inventory
        // - Notify accounting system
        // - Update analytics

        await this.Fire<NotifyAccountsOnOrderAdded>(EventCondition, serviceBusContext);
    }
}
```

**What Happens:**

* **Event Reception**: Receives `OrderAddedEvent` from message bus
* **Side Effects**: Executes business logic (emails, notifications, etc.)
* **Additional Events**: Can fire more events if needed

## Data Transfer Objects (DTOs)

### **Input DTO**: `AddOrderDto`

```csharp
public partial class AddOrderDto : DtoBridge 
{
    [StringLength(100)]
    public string CustomerId { get; set; }

    public ICollection<AddOrderDto_OrderItem> OrderItems { get; set; }
}
```

### **Command**: `AddOrderCommand`

```csharp
public class AddOrderCommand : FlexCommandBridge<AddOrderDto, FlexAppContextBridge>
{
    // Command data is automatically populated by FlexBase
}
```

## Flow Summary

### **Synchronous Flow (Immediate Response)**

1. **POST Request** → Controller receives request
2. **Service Processing** → Business orchestration and PreBus validation
3. **PreBus Plugins** → Sequential validation of business rules
4. **Command Handler** → Data processing and database save
5. **Domain Logic** → Business rules and calculations
6. **Response** → HTTP 201 with order ID

### **Asynchronous Flow (Event Processing)**

1. **Event Publishing** → OrderAddedEvent published to message bus
2. **Subscriber Processing** → NotifyAccountsOnOrderAdded executes
3. **Side Effects** → Emails, notifications, inventory updates
4. **Additional Events** → Can trigger more business processes

## Key Benefits

* **Separation of Concerns**: Each layer has a single responsibility
* **Testability**: Each component can be tested independently
* **Scalability**: Asynchronous processing handles high loads
* **Maintainability**: Clear, readable code structure
* **Event-Driven**: Loose coupling between components

***

**This AddOrder example demonstrates how FlexBase enables clean, maintainable, and scalable insert operations with proper separation of concerns and event-driven architecture!** 🚀


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flexbase.in/solution-structure/getting-started/features/crud/insert-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
