Skip to main content
Version: Next

Batch Operations

Files Referenced in this Document

Table of Contents​

  1. Introduction
  2. Core Component Analysis
  3. Batch Delete Feature Implementation
  4. Clone Feature Implementation
  5. Transaction Consistency and Operation Logs
  6. Performance Optimization Strategies
  7. Call Examples and Exception Handling
  8. Challenges and Solutions in High Concurrency Environments
  9. Conclusion

Introduction​

This document details the technical details of implementing batch delete and clone features in MyEntityNameAppService. It focuses on analyzing the internal logic of the DeleteBatchAsync (referred to as DeleteManyAsync in code) and CloneAsync methods, including how to batch fetch entities via the repository interface IMyEntityNameRepository, handle transaction consistency, and log operations. It also discusses the copying mechanism of core properties during cloning, the generation of new unique identifiers, and the correct reset of audit fields (such as creator, creation time). Furthermore, it discusses performance optimization strategies for batch operations, such as batch processing, asynchronous execution, and database batch support, and provides call examples and exception handling suggestions.

Core Component Analysis​

This section analyzes the core classes and interfaces implementing batch operations.

Diagram sources

Section sources

Batch Delete Feature Implementation​

The DeleteManyAsync method implements batch deletion of multiple entities. This method receives an ID collection of type IEnumerable<Guid>, iterates through each ID, and calls the DeleteAsync method to delete.

Although named "Batch", it actually deletes entities one by one through a loop, rather than using a database-level batch delete operation. This means each deletion triggers a database transaction, which may affect performance. However, this approach allows for better error control—if a deletion fails, exceptions can be caught to decide whether to continue with subsequent deletions.

Diagram sources

Section sources

Clone Feature Implementation​

The CloneAsync method implements entity cloning. Its core logic is as follows:

  1. Get the current maximum sort value sort to assign continuous sort numbers to newly cloned entities.
  2. Traverse the passed ID list and get the original entity via FindAsync.
  3. For each entity, generate a new name: original name + clone tag (defined by MyEntityNameConsts.CloneTag), and check if the new name already exists; if so, append more tags to ensure uniqueness.
  4. Call the entity's Clone method to create a new instance, passing in the new GUID, new name, and incremented sort number.
  5. Insert the new entity into the database via InsertAsync.

During cloning, the Clone method of the MyEntityName class only copies core business properties (Code, Name, Remark, Sort), while audit fields (such as CreatorId, CreationTime) are automatically reset to the current user and current time by the base class FullAuditedAggregateRoot<Guid> upon insertion, ensuring the correctness of audit information.

Diagram sources

Section sources

Transaction Consistency and Operation Logs​

Although DeleteManyAsync and CloneAsync methods themselves do not explicitly use transaction wrappers, since they run within the context of the ABP framework, by default, each repository operation (such as InsertAsync, DeleteAsync) executes in an independent transaction, ensuring atomicity of single operations.

For CloneAsync, although each insertion is an independent transaction, the method internally ensures logical continuity through sequential execution. If full atomicity of all clone operations (i.e., all succeed or all fail) is required, consider explicitly opening a transaction spanning multiple operations using IUnitOfWorkManager in the application service layer.

Regarding operation logs, the ABP framework's audit function (via inheritance of FullAuditedAggregateRoot<Guid>) automatically records the creator, creation time, last modifier, and last modification time of each entity. These information are correctly reset during cloning, reflecting the framework's good support for audit fields.

Section sources

Performance Optimization Strategies​

The current implementation has the following room for performance optimization:

  1. Batch Database Operations: DeleteManyAsync uses loop deletion, which can be optimized to use raw SQL or EF Core's ExecuteDeleteAsync method for true batch deletion, reducing database round trips.
  2. Parallel Processing: For operations without sequential dependencies (such as cloning independent entities), consider using Parallel.ForEachAsync or Task.WhenAll for parallel execution to increase throughput.
  3. Batch Processing: When processing a large number of entities, implement pagination or batching mechanisms to avoid memory overflow caused by loading too much data at once.
  4. Cache Utilization: Introduce a cache layer to reduce database pressure when frequently querying maximum sort numbers or checking if names exist.

The current EfCoreMyEntityNameRepository implements basic query optimization, such as using Specification pattern and dynamic sorting, but does not provide dedicated interfaces for batch operations.

Section sources

Call Examples and Exception Handling​

Call Examples​

// Batch Delete
var idsToDelete = new List<Guid> { id1, id2, id3 };
await myEntityNameAppService.DeleteManyAsync(idsToDelete);

// Batch Clone
var idsToClone = new List<Guid> { id1, id2 };
var clonedEntities = await myEntityNameAppService.CloneAsync(idsToClone);

Exception Handling​

  • Name Conflict: CloneAsync internally checks name uniqueness through a loop to avoid NameAlreadyExists exception.
  • Input Validation: CheckCreateOrUpdateDtoAsync method ensures validity of input data, preventing null values or overly long strings.
  • Concurrency Conflict: Supports optimistic locking via SetConcurrencyStampIfNotNull during entity updates, preventing concurrent modification overwrites.

It is recommended to capture UserFriendlyException at the caller end and display friendly prompts to the user.

Section sources

Challenges and Solutions in High Concurrency Environments​

Challenges​

  1. Sort Conflict: Multiple users adjusting sorting simultaneously may cause AdjustSortAsync calculation errors.
  2. Name Competition: During high-concurrency cloning, name uniqueness checks may have time windows, leading to duplicate names.
  3. Performance Bottleneck: Loop deletion/insertion responds slowly under high load.

Solutions​

  1. Distributed Lock: Add locks to sensitive operations like sort adjustment to ensure serial execution.
  2. Database Constraints: Add unique indexes at the database level as the last line of defense against duplicate names.
  3. Async Queue: Put batch operations into background task queues (such as Hangfire) to avoid blocking the main thread.
  4. Optimistic Locking Enhancement: Add version checking in AdjustSortAsync to improve concurrency safety.

Section sources

Conclusion​

The batch delete and clone features in MyEntityNameAppService implement basic business requirements, utilizing the ABP framework's repository pattern and audit functions to ensure data consistency and traceability. The cloning logic is reasonable, correctly handling unique identifiers and audit field resets. However, the current batch deletion is executed item by item, presenting a performance bottleneck. It is recommended to introduce batch database operations, parallel processing, and distributed lock mechanisms in high concurrency scenarios to improve performance and data security. Future considerations could include optimizing DeleteManyAsync into a true batch operation and providing transactional guarantees for CloneAsync.