# 작업 단위 - Unit Of Work

Unit of Work

#### 설명

연결 및 트랜잭션 관리는 데이터베이스를 사용하는 애플리케이션에서 가장 중요한 개념 중 하나입니다. Axs는 **UOW(UnitOfWOrk)** 시스템을 사용하여 데이터베이스 연결과 트랜잭션을 관리합니다.

![Alt text](/files/wVB7U4yqTu6Q9WmupHcl)

([참고사이트](https://justhackem.wordpress.com/2014/05/25/tdd-using-repository-uow/))

#### 연결과 트랜잭션 관리

Axs는 데이터베이스 연결을 **열고(Open)** **작업 단위 메서드**를 입력 할 때 **트랜잭션**을 **시작**합니다. 이 방법으로 안전하게 연결을 사용할 수 있습니다. 메서드가 끝나면 트랜잭션이 **커밋**되고 연결이 삭제됩니다. 메서드에서 예외가 발생하면 트랜잭션이 **롤백**되고 연결이 **삭제**됩니다.

작업 단위 메서드가 다른 작업 단위 메서드를 호출하면 둘 다 동일한 연결 및 트랜잭션을 사용합니다. 처음 입력 한 방법은 연결 및 트랜잭션을 관리하고 나머지는 이를 재사용합니다.

작업 단위의 기본 **IsolationLevel**은 구성되지 않은 경우 **ReadUncommitted**입니다. 작업 단위 [옵션](#options)을 사용하여 쉽게 구성 할 수 있습니다.

**암묵적인 작업단위 메서드**

아래와 같이 애플리케이션 컨트롤러([application controller](https://github.com/axuslab/docs.axs/blob/main/Developments/Application_Controllers/README.md)) 방법이 있다고 가정합니다.

```csharp
public class SampleAppController : ISampleAppController
{
    private readonly ISampleRepository _sampleRepository;
    private readonly IStatisticsRepository _statisticsRepository;

    public SampleAppController(ISampleRepository sampleRepository, IStatisticsRepository statisticsRepository)
    {
        _sampleRepository = sampleRepository;
        _statisticsRepository = statisticsRepository;
    }

    public void CreateSample(CreateSampleDto input)
    {
        var sample = new Sample { MyName = input.MyName, EmailAddress = input.EmailAddress };
        _sampleRepository.Insert(sample);
        _statisticsRepository.IncrementSampleCount();
    }
}
```

CreateSample 메서드에서 개인 저장소를 사용하는 샘플을 삽입하고 통계 저장소를 사용하여 총 샘플 수를 늘립니다. 애플리케이션 컨트롤러 메서드는 기본적으로 작업 단위이므로 두 저장소 모두 동일한 연결 및 트랜잭션을 **공유**합니다. Axs는 데이터베이스 연결을 열고 CreateSample 메서드를 입력 할 때 트랜잭션을 시작하며 예외가 발생하지 않으면 트랜잭션 끝에서 트랜잭션을 커밋합니다. 예외가 발생하면 모든 것을 롤백합니다.

**UnitOfWork Attribute**

첫 번째이자 선호되는 접근 방식은 **UnitOfWork** 속성을 사용하는 것입니다.

```csharp
[UnitOfWork]
public void CreateSample(CreateSampleDto input)
{
    var sample = new Sample { MyName = input.MyName, EmailAddress = input.EmailAddress };
    _sampleRepository.Insert(sample);
    _statisticsRepository.IncrementSampleCount();
}
```

이렇게하면 CreateSample 메서드가 작업 단위가되어 데이터베이스 연결 및 트랜잭션을 관리합니다. 두 저장소 모두 동일한 작업 단위를 사용합니다.

#### 작업단위 기타 사용 방법

**Unit Of Work 사용 안함**

일반적인 작업 단위 방법에 대해 작업 단위를 비활성화 할 수 있습니다. 이렇게 하려면 UnitOfWorkAttribute의 **IsDisabled** 속성을 사용합니다.

```csharp
[UnitOfWork(IsDisabled = true)]
public virtual void Remove(RemoveDto input)
{
    _otherRepository.Delete(input.Id);
}
```

일부 상황에서는 작업 단위를 비활성화 할 수 있습니다.

**Unit Of Work 트랜잭션 사용 안함**

데이터베이스 수준 트랜잭션을 비활성화 할 수 있습니다.

```csharp
[UnitOfWork(isTransactional: false)]
public GetTasksResult GetTasks(GetTasksDto input)
{
    var tasks = _taskRepository.GetAllWithPeople(input.AssignedId);
    return new GetTasksResult
    {
        Tasks = Mapper.Map<List<TaskDto>>(tasks)
    };
}
```

**자동 반영**

메서드가 작업 단위 인 경우 Axs는 메서드가 끝날 때 모든 변경 사항을 자동으로 저장합니다. 샘플의 이름을 수정하는 코드입니다.

```csharp
[UnitOfWork]
public void UpdateName(UpdateNameDto input)
{
    var sample = _sampleRepository.Get(input.SampleId);
    sample.MyName = input.NewMyName;
}
```

ORM 프레임 워크는 작업 단위에서 엔티티의 모든 변경 사항을 추적하고 이러한 변경 사항을 데이터베이스에 반영합니다. 일반적인 작업 단위 메서드에 대해서는 UnitOfWork 속성을 선언 할 필요가 없습니다.

#### Options

작업 단위의 동작을 변경하는 데 사용할 수있는 몇 가지 옵션이 있습니다.

```csharp
public class SimpleTaskSystemCoreModule : AxsModule
{
    public override void PreInitialize()
    {
        // 작업 단위의 기본 트랜잭션 레벨을 지정한다.
        Configuration.UnitOfWork.IsolationLevel = IsolationLevel.ReadCommitted;
        // 작업 단위 기본 타임아웃 지정
        Configuration.UnitOfWork.Timeout = TimeSpan.FromMinutes(30);
    }
}
```

#### Events

작업 단위에는 **Completed**, **Failed** 및 **Disposed** 이벤트가 있습니다. 이러한 이벤트에 등록하고 필요한 작업을 수행 할 수 있습니다. 예를 들어, 현재 작업 단위가 성공적으로 완료되면 일부 코드를 실행할 수 있습니다.

```csharp
public void CreateTask(CreateTaskDto input)
{
    var task = new Task { Description = input.Description };

    if (input.AssignedPersonId.HasValue)
    {
        task.AssignedPersonId = input.AssignedPersonId.Value;
        // 작업단위가 완료가 될 때 실행하는 코드 등록
        _unitOfWorkManager.Current.Completed += (sender, args) => { /* TODO: 이메일 전송 */ };
    }

    _taskRepository.Insert(task);
}
```

#### 확인

UOW를 테스트 시 속성을 통한 사용과 UnitOfWorkManager를 사용하여 각각 테스트를 진행할 수 있습니다.

**스웨거에서 확인**

스웨거에서 아래 주소로 호출하면 테스트를 할 수 있습니다.

**1. 정상 입력 시나리오**

**/api/services/app/Sample/CreateSampleUOW**

![picture 1](/files/0eAnt0CRLm6yZ0UpGNdQ)

데이터가 정상적으로 들어 갔는지 확인은 아래 주소에서 확인하면 됩니다.

**/api/services/app/Sample/GetAll**

![picture 3](/files/aJJuXMPOe6liDJdtoFL0)

데이터 확인

![picture 4](/files/DD37y2lX5loefd3dt28d)

최근에 들어간 데이터를 확인할 수 있습니다.

**2. 에러 발생 입력 시나리오**

**/api/services/app/Sample/CreateSampleUOWEx**

![picture 6](/files/jvDmPWBLt3JDRT89ulLE)

![picture 7](/files/TRfIpwTGIBzfkIRhEV3j)

데이터 확인

에러가 발생이 되어 입력된 데이터가 추가 되지 않은 것을 확인하면 됩니다.

UOW 관련 테스트는 아래 스웨거에서 확인할 수 있습니다.

![picture 5](/files/Xbq7YuDsVkGMC7lULCwD)


---

# 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.axuslab.com/2.-domain-layer/unit_of_work.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.
