From 7825fc1e3788b7b670e2a55bf4e16313d9204ef8 Mon Sep 17 00:00:00 2001 From: Kamran Sadin Date: Sun, 22 Jun 2025 00:38:08 +0330 Subject: [PATCH 1/2] Add CancellationToken to Repository methods --- .../GenericRepository/GenericRepository.cs | 42 +++++++++++++------ .../GenericRepository/IGenericRepository.cs | 16 ++++--- .../GenericRepository/IRepository.cs | 18 +++++--- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/KSFramework/GenericRepository/GenericRepository.cs b/src/KSFramework/GenericRepository/GenericRepository.cs index 448ecd9..3a109b1 100644 --- a/src/KSFramework/GenericRepository/GenericRepository.cs +++ b/src/KSFramework/GenericRepository/GenericRepository.cs @@ -23,20 +23,24 @@ public GenericRepository(DbContext context) : base(context) /// Gets an entity by its primary key. /// /// The entity ID. + /// /// The entity if found; otherwise, null. - public async ValueTask GetByIdAsync(object id) + public async ValueTask GetByIdAsync(object id, + CancellationToken cancellationToken = default) { - return await DbSet.FindAsync(id); + return await DbSet.FindAsync(id, cancellationToken); } /// /// Gets all entities. /// /// Whether to disable tracking for better performance. + /// /// A list of all entities. - public async Task> GetAllAsync(bool asNoTracking = true) + public async Task> GetAllAsync(bool asNoTracking = true, + CancellationToken cancellationToken = default) { - return await AsQueryable(asNoTracking).ToListAsync(); + return await AsQueryable(asNoTracking).ToListAsync(cancellationToken); } /// @@ -48,7 +52,11 @@ public async Task> GetAllAsync(bool asNoTracking = true) /// Property name to order by. /// Order descending if true. /// A paginated list of entities. - public async Task> GetPagedAsync(int pageIndex, int pageSize, Expression>? where = null, string? orderBy = "", bool desc = false) + public async Task> GetPagedAsync(int pageIndex, + int pageSize, + Expression>? where = null, + string? orderBy = "", + bool desc = false) { var query = ApplyWhere(AsQueryable(), where); return await PaginatedList.CreateAsync(query, pageIndex, pageSize, where, orderBy, desc); @@ -84,28 +92,34 @@ public IEnumerable Find(Expression> predicate, bool /// Gets a single entity that matches the given predicate or null. /// /// The filter expression. + /// /// The matching entity or null. - public async Task SingleOrDefaultAsync(Expression> predicate) + public async Task SingleOrDefaultAsync(Expression> predicate, + CancellationToken cancellationToken = default) { - return await DbSet.SingleOrDefaultAsync(predicate); + return await DbSet.SingleOrDefaultAsync(predicate, cancellationToken); } /// /// Adds a new entity asynchronously. /// /// The entity to add. - public async Task AddAsync(TEntity entity) + /// + public async Task AddAsync(TEntity entity, + CancellationToken cancellationToken = default) { - await DbSet.AddAsync(entity); + await DbSet.AddAsync(entity, cancellationToken); } /// /// Adds a range of entities asynchronously. /// /// The entities to add. - public async Task AddRangeAsync(IEnumerable entities) + /// + public async Task AddRangeAsync(IEnumerable entities, + CancellationToken cancellationToken = default) { - await DbSet.AddRangeAsync(entities); + await DbSet.AddRangeAsync(entities, cancellationToken); } /// @@ -139,9 +153,11 @@ public void RemoveRange(IEnumerable entities) /// Determines whether any entity exists that matches the specified predicate. /// /// The condition to check. + /// /// True if at least one entity exists; otherwise, false. - public async Task IsExistValueForPropertyAsync(Expression> predicate) + public async Task IsExistValueForPropertyAsync(Expression> predicate, + CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(predicate); + return await DbSet.AnyAsync(predicate, cancellationToken); } } \ No newline at end of file diff --git a/src/KSFramework/GenericRepository/IGenericRepository.cs b/src/KSFramework/GenericRepository/IGenericRepository.cs index 52cd222..f769604 100644 --- a/src/KSFramework/GenericRepository/IGenericRepository.cs +++ b/src/KSFramework/GenericRepository/IGenericRepository.cs @@ -14,14 +14,14 @@ public interface IGenericRepository where TEntity : class /// /// The unique identifier of the entity. /// A task representing the asynchronous operation, containing the entity if found; otherwise, null. - ValueTask GetByIdAsync(object id); + ValueTask GetByIdAsync(object id, CancellationToken cancellationToken = default); /// /// Asynchronously retrieves all entities. /// /// Whether to track entities in change tracker. /// A task containing all entities. - Task> GetAllAsync(bool asNoTracking = true); + Task> GetAllAsync(bool asNoTracking = true, CancellationToken cancellationToken = default); /// /// Asynchronously retrieves a paginated list of entities with optional filtering and ordering. @@ -68,19 +68,21 @@ PaginatedList GetPaged( /// /// The condition to match. /// A task containing a single entity or null. - Task SingleOrDefaultAsync(Expression> predicate); + Task SingleOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default); /// /// Asynchronously adds an entity to the repository. /// /// The entity to add. - Task AddAsync(TEntity entity); + /// + Task AddAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Asynchronously adds multiple entities to the repository. /// /// The entities to add. - Task AddRangeAsync(IEnumerable entities); + /// + Task AddRangeAsync(IEnumerable entities, CancellationToken cancellationToken = default); /// /// Updates an existing entity in the repository. @@ -104,6 +106,8 @@ PaginatedList GetPaged( /// Asynchronously checks whether any entity matches the given predicate. /// /// The condition to match. + /// /// True if any entity matches; otherwise, false. - Task IsExistValueForPropertyAsync(Expression> predicate); + Task IsExistValueForPropertyAsync(Expression> predicate, + CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/KSFramework/GenericRepository/IRepository.cs b/src/KSFramework/GenericRepository/IRepository.cs index 75bdaef..d099325 100644 --- a/src/KSFramework/GenericRepository/IRepository.cs +++ b/src/KSFramework/GenericRepository/IRepository.cs @@ -9,10 +9,13 @@ namespace KSFramework.GenericRepository; /// The entity type. public interface IRepository where TEntity : class { - Task AddAsync(TEntity entity); - Task AddRangeAsync(IEnumerable entities); + Task AddAsync(TEntity entity, + CancellationToken cancellationToken = default); + Task AddRangeAsync(IEnumerable entities, + CancellationToken cancellationToken = default); IEnumerable Find(Expression> predicate, bool asNoTracking = true); - Task> GetAllAsync(bool asNoTracking = true); + Task> GetAllAsync(bool asNoTracking = true, + CancellationToken cancellationToken = default); Task> GetPagedAsync( int pageIndex, int pageSize, @@ -25,10 +28,13 @@ PaginatedList GetPaged( Expression>? where = null, string? orderBy = "", bool desc = false); - ValueTask GetByIdAsync(object id); + ValueTask GetByIdAsync(object id, + CancellationToken cancellationToken = default); void Remove(TEntity entity); void RemoveRange(IEnumerable entities); - Task SingleOrDefaultAsync(Expression> predicate); - Task IsExistValueForPropertyAsync(Expression> predicate); + Task SingleOrDefaultAsync(Expression> predicate, + CancellationToken cancellationToken = default); + Task IsExistValueForPropertyAsync(Expression> predicate, + CancellationToken cancellationToken = default); void Update(TEntity entity); } \ No newline at end of file From 1e212d666ed9562846301b33e4f4a69c4354c8ee Mon Sep 17 00:00:00 2001 From: Kamran Sadin Date: Sun, 22 Jun 2025 12:28:31 +0330 Subject: [PATCH 2/2] Add CancellationToken to GenericRepository GetPaged methods --- .../GenericRepository/GenericRepository.cs | 6 ++++-- .../GenericRepository/IGenericRepository.cs | 6 +++++- src/KSFramework/Pagination/PaginatedList.cs | 14 ++++++++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/KSFramework/GenericRepository/GenericRepository.cs b/src/KSFramework/GenericRepository/GenericRepository.cs index 3a109b1..afad026 100644 --- a/src/KSFramework/GenericRepository/GenericRepository.cs +++ b/src/KSFramework/GenericRepository/GenericRepository.cs @@ -51,15 +51,17 @@ public async Task> GetAllAsync(bool asNoTracking = true, /// Optional filter expression. /// Property name to order by. /// Order descending if true. + /// /// A paginated list of entities. public async Task> GetPagedAsync(int pageIndex, int pageSize, Expression>? where = null, string? orderBy = "", - bool desc = false) + bool desc = false, + CancellationToken cancellationToken = default) { var query = ApplyWhere(AsQueryable(), where); - return await PaginatedList.CreateAsync(query, pageIndex, pageSize, where, orderBy, desc); + return await PaginatedList.CreateAsync(query, pageIndex, pageSize, where, orderBy, desc, cancellationToken); } /// diff --git a/src/KSFramework/GenericRepository/IGenericRepository.cs b/src/KSFramework/GenericRepository/IGenericRepository.cs index f769604..da8dcc5 100644 --- a/src/KSFramework/GenericRepository/IGenericRepository.cs +++ b/src/KSFramework/GenericRepository/IGenericRepository.cs @@ -13,6 +13,7 @@ public interface IGenericRepository where TEntity : class /// Asynchronously retrieves an entity by its unique identifier. /// /// The unique identifier of the entity. + /// /// A task representing the asynchronous operation, containing the entity if found; otherwise, null. ValueTask GetByIdAsync(object id, CancellationToken cancellationToken = default); @@ -20,6 +21,7 @@ public interface IGenericRepository where TEntity : class /// Asynchronously retrieves all entities. /// /// Whether to track entities in change tracker. + /// /// A task containing all entities. Task> GetAllAsync(bool asNoTracking = true, CancellationToken cancellationToken = default); @@ -31,13 +33,15 @@ public interface IGenericRepository where TEntity : class /// Optional filter expression. /// Optional property name to order by. /// Indicates if the order should be descending. + /// /// A task containing a paginated list of entities. Task> GetPagedAsync( int pageIndex, int pageSize, Expression>? where = null, string? orderBy = "", - bool desc = false); + bool desc = false, + CancellationToken cancellationToken = default); /// /// Retrieves a paginated list of entities with optional filtering and ordering. diff --git a/src/KSFramework/Pagination/PaginatedList.cs b/src/KSFramework/Pagination/PaginatedList.cs index 7a053a8..470a8f5 100644 --- a/src/KSFramework/Pagination/PaginatedList.cs +++ b/src/KSFramework/Pagination/PaginatedList.cs @@ -37,8 +37,14 @@ public bool HasNextPage } } - public static async Task> CreateAsync(IQueryable source, int pageIndex, int pageSize, Expression>? where = null, - string? orderBy = "", bool desc = false) + public static async Task> CreateAsync( + IQueryable source, + int pageIndex, + int pageSize, + Expression>? where = null, + string? orderBy = "", + bool desc = false, + CancellationToken cancellationToken = default) { if(where is null) where = x => true; @@ -54,8 +60,8 @@ public static async Task> CreateAsync(IQueryable source, int } } - var count = await source.CountAsync(where); - var items = await source.Where(where).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(); + var count = await source.CountAsync(where, cancellationToken); + var items = await source.Where(where).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(cancellationToken); return new PaginatedList(items, count, pageIndex, pageSize); }