# Service Search Patterns

## Search Method Pattern

Tất cả service Search methods phải tuân thủ pattern sau:

### 1. Query Building
```csharp
public async Task<SmartTableResult<ItemType>> Search(SmartTableParam param)
{
    IQueryable<EntityType> query = _repository.Query()
        .Include(x => x.RelatedEntity1)
        .Include(x => x.RelatedEntity2)
        .Where(x => !x.IsDeleted); // Nếu có soft delete

    // Lọc theo từ khóa tìm kiếm
    if (param.Search.PredicateObject != null)
    {
        dynamic search = param.Search.PredicateObject;

        if (search.Keyword != null)
        {
            string keyword = search.Keyword;
            keyword = keyword.Trim().ToLower();
            query = query.Where(x => 
                x.Property1.Contains(keyword) ||
                x.Property2.ToLower().Contains(keyword) ||
                (x.RelatedEntity != null && x.RelatedEntity.Property.ToLower().Contains(keyword)));
        }

        // Các filter khác...
        if (search.FilterProperty != null)
        {
            query = query.Where(x => x.FilterProperty == search.FilterProperty);
        }
    }
}
```

### 2. Sorting Pattern
```csharp
// Sắp xếp mặc định - SmartTableExtension sẽ xử lý sorting
param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };
```

### 3. Pagination Pattern
```csharp
// Sắp xếp mặc định
param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };

// Sử dụng SmartTableExtension để xử lý phân trang
return await query.ToSmartTableResultAsync(param, entity => entity.ToItem());
```

## AutoMapper Usage

### 1. Mapping Configuration
```csharp
// Trong mapping profile
CreateMap<Entity, Item>()
    .ForMember(dest => dest.RelatedProperty, opt => opt.MapFrom(src => src.RelatedEntity != null ? src.RelatedEntity.Property : ""))
    .ForMember(dest => dest.CalculatedProperty, opt => opt.MapFrom(src => src.Collection.Count(x => !x.IsDeleted)));
```

### 2. Service Usage
```csharp
// Sử dụng AutoMapper extension methods
var items = entities.Select(x => x.ToItem()).ToList();
var model = entity.ToModel();
var entity = model.ToEntity();
```

## Key Rules

1. **Luôn sử dụng AutoMapper** cho việc convert entity sang DTO
2. **Không tạo DTO thủ công** trong service methods
3. **Include các related entities** cần thiết cho mapping
4. **Xử lý null reference** khi access related properties
5. **Sắp xếp mặc định** theo CreatedTime descending
6. **Đếm totalCount trước** khi phân trang
7. **Sử dụng Skip/Take** cho phân trang
8. **Convert sang DTO sau** khi đã có entities

## Anti-Patterns

❌ **KHÔNG làm như này:**
```csharp
// Tạo DTO thủ công
var items = await query
    .Select(x => new ItemType
    {
        Id = x.Id,
        Property1 = x.Property1,
        // ... nhiều properties
    })
    .ToListAsync();
```

✅ **Làm như này:**
```csharp
// Sử dụng AutoMapper
var entities = await query.ToListAsync();
var items = entities.Select(x => x.ToItem()).ToList();
```
