diff --git a/docs/en/Repositories.md b/docs/en/Repositories.md index dc82876efb..a1a5ac5cce 100644 --- a/docs/en/Repositories.md +++ b/docs/en/Repositories.md @@ -164,6 +164,10 @@ If your entity is a soft-delete entity, you can use the `HardDeleteAsync` method > See the [Data Filtering](Data-Filtering.md) documentation for more about soft-delete. +### Ensure Entities Exists + +The `EnsureExistsAsync` extension method accepts entity id or entities query expression to ensure entities exist, otherwise, it will throw `EntityNotFoundException`. + ## Other Generic Repository Types Standard `IRepository` interface exposes the standard `IQueryable` and you can freely query using the standard LINQ methods. This is fine for most of the applications. However, some ORM providers or database systems may not support standard `IQueryable` interface. If you want to use such providers, you can't rely on the `IQueryable`. diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs index 2b4dd70e62..379203f46a 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.Domain.Repositories; public static class RepositoryExtensions { - public static async Task EnsureCollectionLoadedAsync( + public async static Task EnsureCollectionLoadedAsync( this IBasicRepository repository, TEntity entity, Expression>> propertyExpression, @@ -31,7 +31,7 @@ public static class RepositoryExtensions } } - public static async Task EnsurePropertyLoadedAsync( + public async static Task EnsurePropertyLoadedAsync( this IBasicRepository repository, TEntity entity, Expression> propertyExpression, @@ -47,7 +47,33 @@ public static class RepositoryExtensions } } - public static async Task HardDeleteAsync( + public async static Task EnsureExistsAsync( + this IRepository repository, + TKey id, + CancellationToken cancellationToken = default + ) + where TEntity : class, IEntity + { + if (!await repository.AnyAsync(x => x.Id.Equals(id), cancellationToken)) + { + throw new EntityNotFoundException(typeof(TEntity), id); + } + } + + public async static Task EnsureExistsAsync( + this IRepository repository, + Expression> expression, + CancellationToken cancellationToken = default + ) + where TEntity : class, IEntity + { + if (!await repository.AnyAsync(expression, cancellationToken)) + { + throw new EntityNotFoundException(typeof(TEntity)); + } + } + + public async static Task HardDeleteAsync( this IRepository repository, Expression> predicate, bool autoSave = false, @@ -71,7 +97,7 @@ public static class RepositoryExtensions } } - public static async Task HardDeleteAsync( + public async static Task HardDeleteAsync( this IBasicRepository repository, IEnumerable entities, bool autoSave = false, @@ -95,7 +121,7 @@ public static class RepositoryExtensions } } - public static async Task HardDeleteAsync( + public async static Task HardDeleteAsync( this IBasicRepository repository, TEntity entity, bool autoSave = false, @@ -139,7 +165,7 @@ public static class RepositoryExtensions return unitOfWorkManagerAccessor.UnitOfWorkManager; } - private static async Task HardDeleteWithUnitOfWorkAsync( + private async static Task HardDeleteWithUnitOfWorkAsync( IRepository repository, Expression> predicate, bool autoSave, @@ -155,7 +181,7 @@ public static class RepositoryExtensions } } - private static async Task HardDeleteWithUnitOfWorkAsync( + private async static Task HardDeleteWithUnitOfWorkAsync( IBasicRepository repository, IEnumerable entities, bool autoSave, @@ -173,7 +199,7 @@ public static class RepositoryExtensions await repository.DeleteManyAsync(entities, autoSave, cancellationToken); } - private static async Task HardDeleteWithUnitOfWorkAsync( + private async static Task HardDeleteWithUnitOfWorkAsync( IBasicRepository repository, TEntity entity, bool autoSave, diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/RepositoryExtensions_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/RepositoryExtensions_Tests.cs new file mode 100644 index 0000000000..70f99ac26a --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/RepositoryExtensions_Tests.cs @@ -0,0 +1,8 @@ +using Volo.Abp.TestApp.Testing; + +namespace Volo.Abp.EntityFrameworkCore.Repositories; + +public class RepositoryExtensions_Tests : RepositoryExtensions_Tests +{ + +} diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/Repositories/RepositoryExtensions_Tests.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/Repositories/RepositoryExtensions_Tests.cs new file mode 100644 index 0000000000..dbb37bb71e --- /dev/null +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/Repositories/RepositoryExtensions_Tests.cs @@ -0,0 +1,8 @@ +using Volo.Abp.TestApp.Testing; + +namespace Volo.Abp.MemoryDb.Repositories; + +public class RepositoryExtensions_Tests : RepositoryExtensions_Tests +{ + +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/RepositoryExtensions_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/RepositoryExtensions_Tests.cs new file mode 100644 index 0000000000..dd653878b8 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/RepositoryExtensions_Tests.cs @@ -0,0 +1,10 @@ +using Volo.Abp.TestApp.Testing; +using Xunit; + +namespace Volo.Abp.MongoDB.Repositories; + +[Collection(MongoTestCollection.Name)] +public class RepositoryExtensions_Tests : RepositoryExtensions_Tests +{ + +} diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/RepositoryExtensions_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/RepositoryExtensions_Tests.cs new file mode 100644 index 0000000000..747c53e333 --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/RepositoryExtensions_Tests.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Modularity; +using Volo.Abp.TestApp.Domain; +using Xunit; + +namespace Volo.Abp.TestApp.Testing; + +public abstract class RepositoryExtensions_Tests : TestAppTestBase + where TStartupModule : IAbpModule +{ + protected readonly IRepository PersonRepository; + + protected RepositoryExtensions_Tests() + { + PersonRepository = GetRequiredService>(); + } + + [Fact] + public async Task EnsureExistsAsync_Test() + { + await WithUnitOfWorkAsync(async () => + { + var id = Guid.NewGuid(); + await Assert.ThrowsAsync(async () => + await PersonRepository.EnsureExistsAsync(Guid.NewGuid()) + ); + await Assert.ThrowsAsync(async () => + await PersonRepository.EnsureExistsAsync(x => x.Id == id) + ); + + await PersonRepository.EnsureExistsAsync(TestDataBuilder.UserDouglasId); + await PersonRepository.EnsureExistsAsync(x => x.Id == TestDataBuilder.UserDouglasId); + }); + } +}