diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs index 2115d00200..e84778ae50 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; @@ -12,7 +14,7 @@ public static class RepositoryAsyncExtensions { #region Contains - public static async Task ContainsAsync( + public async static Task ContainsAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] T item, CancellationToken cancellationToken = default) @@ -26,7 +28,7 @@ public static class RepositoryAsyncExtensions #region Any/All - public static async Task AnyAsync( + public async static Task AnyAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -35,7 +37,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AnyAsync(queryable, cancellationToken); } - public static async Task AnyAsync( + public async static Task AnyAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -45,7 +47,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AnyAsync(queryable, predicate, cancellationToken); } - public static async Task AllAsync( + public async static Task AllAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -59,7 +61,7 @@ public static class RepositoryAsyncExtensions #region Count/LongCount - public static async Task CountAsync( + public async static Task CountAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -68,7 +70,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.CountAsync(queryable, cancellationToken); } - public static async Task CountAsync( + public async static Task CountAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -78,7 +80,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.CountAsync(queryable, predicate, cancellationToken); } - public static async Task LongCountAsync( + public async static Task LongCountAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -87,7 +89,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.LongCountAsync(queryable, cancellationToken); } - public static async Task LongCountAsync( + public async static Task LongCountAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -101,41 +103,41 @@ public static class RepositoryAsyncExtensions #region First/FirstOrDefault - public static async Task FirstAsync( + public async static Task FirstAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstAsync(queryable, cancellationToken); } - public static async Task FirstAsync( + public async static Task FirstAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstAsync(queryable, predicate, cancellationToken); } - public static async Task FirstOrDefaultAsync( + public async static Task FirstOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstOrDefaultAsync(queryable, cancellationToken); } - public static async Task FirstOrDefaultAsync( + public async static Task FirstOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstOrDefaultAsync(queryable, predicate, cancellationToken); } @@ -143,49 +145,63 @@ public static class RepositoryAsyncExtensions #region Last/LastOrDefault - public static async Task LastAsync( + public async static Task LastAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastAsync(queryable, cancellationToken); } - public static async Task LastAsync( + public async static Task LastAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastAsync(queryable, predicate, cancellationToken); } - public static async Task LastOrDefaultAsync( + public async static Task LastOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastOrDefaultAsync(queryable, cancellationToken); } - public static async Task LastOrDefaultAsync( + public async static Task LastOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastOrDefaultAsync(queryable, predicate, cancellationToken); } #endregion + #region OrderById + + private static IQueryable AddOrderById([NotNull] this IQueryable queryable) + where T : class, IEntity + { + if (typeof(T).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntity<>))) + { + queryable = queryable.OrderBy(nameof(IEntity.Id)); + } + return queryable; + } + + #endregion + #region Single/SingleOrDefault - public static async Task SingleAsync( + public async static Task SingleAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -194,7 +210,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleAsync(queryable, cancellationToken); } - public static async Task SingleAsync( + public async static Task SingleAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -204,7 +220,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleAsync(queryable, predicate, cancellationToken); } - public static async Task SingleOrDefaultAsync( + public async static Task SingleOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -213,7 +229,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleOrDefaultAsync(queryable, cancellationToken); } - public static async Task SingleOrDefaultAsync( + public async static Task SingleOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -227,7 +243,7 @@ public static class RepositoryAsyncExtensions #region Min - public static async Task MinAsync( + public async static Task MinAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -236,7 +252,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.MinAsync(queryable, cancellationToken); } - public static async Task MinAsync( + public async static Task MinAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -250,7 +266,7 @@ public static class RepositoryAsyncExtensions #region Max - public static async Task MaxAsync( + public async static Task MaxAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -259,7 +275,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.MaxAsync(queryable, cancellationToken); } - public static async Task MaxAsync( + public async static Task MaxAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -273,7 +289,7 @@ public static class RepositoryAsyncExtensions #region Sum - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -283,7 +299,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -293,7 +309,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -303,7 +319,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -313,7 +329,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -323,7 +339,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -333,7 +349,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -343,7 +359,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -353,7 +369,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -363,7 +379,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -377,7 +393,7 @@ public static class RepositoryAsyncExtensions #region Average - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -387,7 +403,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -397,7 +413,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -407,7 +423,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -417,7 +433,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -427,7 +443,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -437,7 +453,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -447,7 +463,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -457,7 +473,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -471,7 +487,7 @@ public static class RepositoryAsyncExtensions #region ToList/Array - public static async Task> ToListAsync( + public async static Task> ToListAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -480,7 +496,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.ToListAsync(queryable, cancellationToken); } - public static async Task ToArrayAsync( + public async static Task ToArrayAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs index 4c3b355367..2666695fd9 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Shouldly; using Volo.Abp.Domain.Repositories; using Volo.Abp.TestApp.Domain; @@ -55,4 +56,20 @@ public class EfCoreAsyncQueryableProvider_Tests : EntityFrameworkCoreTestBase await uow.CompleteAsync(); } } + + [Fact] + public async Task LastOrDefaultAsync_With_DefaultOrderBy() + { + using (var uow = _unitOfWorkManager.Begin()) + { + var lastOrDefault = await _personRepository.LastOrDefaultAsync(); + lastOrDefault.ShouldNotBeNull(); + + await Assert.ThrowsAsync(async () => + await (await _personRepository.GetQueryableAsync()).LastOrDefaultAsync() + ); + + await uow.CompleteAsync(); + } + } }