---
title: IUnitOfWork
slug: configured-commerce/docs/iunitofwork
docTags: 
createdAt: 2026-08-13T10:46:25.000Z
---

## Description

The IUnitOfWork interface is the abstraction layer to the object session management of the system.

The first time the UnitOfWork is accessed, it will create an instance of the UnitOfWork in HttpContext.Current.Items which lasts for the current web request. Subsequent access of UnitOfWork will return this instance.

## Transactional behavior

A single `Save` or `SaveAsync` call is atomic: Entity Framework wraps that one batch of changes in its own implicit database transaction.

The grouping of *multiple* saves into a transaction differs by framework:

- **.NET Framework 4.8** – wrapped each request's entire handler chain in one transaction and performed a final Save and commit. A handler exception rolled everything back.
- **.NET 8.0+** removed this automatic wrapping. Changes still persist, because any `Save` flushes all pending changes on the shared session. However, each `Save` commits immediately in its own implicit transaction, instead of committing together at the end of the chain. Multiple saves are atomic only if you manage the transaction explicitly with `BeginTransaction`, `CommitTransaction`, and `RollbackTransaction` (see the example under [BeginTransaction()](docId\:Sh1Te5TmSjD2ck5gkJf6L)).

:::hint{type="danger"}
**❗️ Important**
If your extension depends on several `Save` calls succeeding or failing together, do not rely on the framework — wrap them in an explicit transaction. See [Transactions and the unit of work](docId\:p3YkdL3n05GsjwOJy-DoY) and the [.NET 4.8 framework to .NET 8.0+ migration](docId\:yR5txbyljjyNjPSMiVTeG) guide.
:::

## Properties

### DataProvider

The Persistant Data Provider.

```csharp
IDataProvider DataProvider {get;}
```

## Methods

### BeginTransaction()

This method starts a Database Transaction.

```csharp
void BeginTransaction()
```

**Example**

Below is the typical usage of this method along with the other methods that handle the lifetime of a database transaction.

Code Sample

```csharp
this.UnitOfWork.BeginTransaction();
try
{
    foreach (var contentKey in contentKeys)
    {
        this.RecursiveDelete(contentKey, isVariant);
    }
 
    this.UnitOfWork.Save();
    this.UnitOfWork.CommitTransaction();
}
catch (Exception)
{
    this.UnitOfWork.RollbackTransaction();
    throw;
}
```

### BeginTransaction(IsolationLevel)

This method starts a Database Transaction using the specified isolation level.

```csharp
void BeginTransaction(IsolationLevel isolationLevel)
```

**Parameters**

- **isolationLevel** – Isolation level.

### Clear(bool)

This method clears the objects out of the UnitOfWork session, the objects will still be valid objects, but they will no longer be persisted to the database. This method is useful when working with large sets of data for example during a refresh.

```csharp
void Clear(bool dispose = true)
```

**Parameters**

- **dispose** – If true, the underlying data provider will be disposed.

### Close()

Close the Session.

```csharp
void Close()
```

### CommitTransaction()

Commits a previously started Database Transaction.

```csharp
void CommitTransaction()
```

### EagerLoad(object)

Forces a load of a proxy, does not cascade.

```csharp
void EagerLoad(object obj)
```

**Parameters**

- **obj** – The obj.

### Evict(object)

Removes a single object from the UnitOfWork session. The object is still a valid object, but will no longer persist to the database.

```csharp
void Evict(object obj)
```

**Parameters**

- **obj** – The obj.

### GetRepository(Type)

Returns an IRepository for an object that will be tracked within this UnitOfWork's session.

```csharp
IRepository GetRepository(Type type)
```

**Parameters**

- **type** – The type.

**Returns**

- The IRepository.

### GetRepository`<T>`()

Returns an IRepository for an object that will be tracked within this UnitOfWork's session.

```csharp
IRepository<T> GetRepository<T>()
```

**Returns**

- The IRepository.

**Type Constraints**

- T : class, IBusinessObject

**Remarks**

Unlike the GetTypedRepository`<T>` method, this method returns a generic repository, rather than a specific repository, that operates on a specific business object.

**Example**

The example below uses the GetRepository`<T>` method to return an IRepository`<CustomerOrder>` to delete a specific customer order.

Code Sample

```csharp
public override RemoveCartResult Execute(IUnitOfWork unitOfWork, RemoveCartParameter parameter, RemoveCartResult result)
    {
        var cart = result.GetCartResult.Cart;
        if (cart.Id == Guid.Empty || cart.Status == CustomerOrder.StatusType.Void)
        {
            return this.NextHandler.Execute(unitOfWork, parameter, result);
        }
     
        unitOfWork.GetRepository<CustomerOrder>().Delete(result.GetCartResult.Cart);
     
        return this.NextHandler.Execute(unitOfWork, parameter, result);
    }
```

### GetTypedRepository`<T>`()

Returns a specific type of IRepository that will be tracked within this UnitOfWork's session.

```csharp
T GetTypedRepository<T>()
```

**Returns**

The repository.

**Type** Constraints

T : class, IRepository

**Remarks**

This method is useful if you need to use a method on a repository that is specific to that repository implementation. For example, the IUserProfileRepository has a method GetByUserName that finds a user by username rather than by id, which is another way to retrieve an object from the database.

**Example**

The example below validates the email address when creating a new account. The GetTypedRepository`<T>`() method is used to return the IUserProfileRepository and check if the email address is already being used by another user.

Code Sample

```csharp
public override AddAccountResult Execute(IUnitOfWork unitOfWork, AddAccountParameter parameter, AddAccountResult result)
    {
        if (!RegularExpressionLibrary.IsValidEmail(parameter.Email))
        {
            return this.CreateErrorServiceResult(
                result,
                SubCode.InvalidEmailAddress,
                MessageProvider.Current.UpdateAccountInfo_EmailAddress_ValidEmail);
        }
     
        if (this.authenticationService.Value.RequiresUniqueEmail())
        {
            var emailAlreadyExists = unitOfWork.GetTypedRepository<IUserProfileRepository>().GetTable().Any(o => o.Email.Equals(parameter.Email));
     
            if (emailAlreadyExists)
            {
                return this.CreateErrorServiceResult(
                    result,
                    SubCode.AccountServiceEmailAlreadyExists,
                    MessageProvider.Current.CreateNewAccountInfo_EmailAddress_AlreadyExists);
            }
        }
     
        return this.NextHandler.Execute(unitOfWork, parameter, result);
    }
```

### Reattach`<T>`(T)

Reattaches a previously Evicted object to the session.

```csharp
void Reattach<T>(T value)
```

**Parameters**

- **value** – The value.

**Type Constraints**

- T : class, IBusinessObject

### Refresh`<T>`(T)

Refresh an object from the database.

```csharp
void Refresh<T>(T obj)
```

**Parameters**

- **obj** – The obj.

**Type Constraints**

- T : class, IBusinessObject

### RollbackTransaction()

Rolls back a previously started Database Transaction

```csharp
void RollbackTransaction()
```

### Save()

Saves all of the changes in the current UnitOfWork session to the Database.

```csharp
void Save()
```

**Remarks**

This method is typically called after updating or deleting existing business objects or creating new business objects.

**Example**

The example below adds a new bill-to customer based on data sent along with the API request.

Code Sample

```csharp
public override AddBillToResult Execute(IUnitOfWork unitOfWork, AddBillToParameter parameter, AddBillToResult result)
    {
        var customerRepository = unitOfWork.GetRepository<Customer>();
     
        var billTo = customerRepository.Create();
        var setBillToInitialValuesResult = this.customerPipeline.SetBillToInitialValues(new SetBillToInitialValuesParameter(billTo));
        if (setBillToInitialValuesResult.ResultCode != ResultCode.Success)
        {
            return this.CreateErrorServiceResult(result, setBillToInitialValuesResult.SubCode, setBillToInitialValuesResult.Message);
        }
     
        billTo.IsGuest = parameter.IsGuest;
        billTo.FirstName = parameter.FirstName ?? string.Empty;
        billTo.LastName = parameter.LastName ?? string.Empty;
        billTo.CompanyName = parameter.CompanyName ?? string.Empty;
        billTo.Attention = parameter.Attention ?? string.Empty;
        billTo.Address1 = parameter.Address1 ?? string.Empty;
        billTo.Address2 = parameter.Address2 ?? string.Empty;
        billTo.Address3 = parameter.Address3 ?? string.Empty;
        billTo.Address4 = parameter.Address4 ?? string.Empty;
        billTo.City = parameter.City ?? string.Empty;
        billTo.PostalCode = parameter.PostalCode ?? string.Empty;
        billTo.Phone = parameter.Phone ?? string.Empty;
        billTo.Fax = parameter.Fax ?? string.Empty;
        billTo.Email = parameter.Email ?? string.Empty;
     
        this.customerUtilities.SetCountry(unitOfWork, parameter.CountryId, billTo);
        this.customerUtilities.SetState(unitOfWork, parameter.StateId, billTo);
     
        customerRepository.Insert(billTo);
        unitOfWork.Save();
     
        result.BillTo = billTo;
     
        return this.NextHandler.Execute(unitOfWork, parameter, result);
    }
```

### SaveAsync()

Saves all of the changes in the object in the current UnitOfWork session to the Database async.

### Task SaveAsync()

**Returns**

- The Task.

### SaveWithoutChangeTracking(Action)

Saves all of the changes in the current UnitOfWork session to the Database executing the passed in action while Change Tracking is disabled.

```csharp
void SaveWithoutChangeTracking(Action action)
```

**Parameters**

- **action** – The action.

### UnProxy(object)

Convert a proxied object into the real thing.

```csharp
object UnProxy(object obj)
```

**Parameters**

- **obj** – The obj.

**Returns**

- The object.
