Browse Source

Add a default sort for `First/FirstOrDefault` and `Last/LastOrDefault`.

pull/22888/head
maliming 9 months ago
parent
commit
780f71131c
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 122
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs
  2. 17
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs

122
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<bool> ContainsAsync<T>(
public async static Task<bool> ContainsAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] T item,
CancellationToken cancellationToken = default)
@ -26,7 +28,7 @@ public static class RepositoryAsyncExtensions
#region Any/All
public static async Task<bool> AnyAsync<T>(
public async static Task<bool> AnyAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<bool> AnyAsync<T>(
public async static Task<bool> AnyAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -45,7 +47,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AnyAsync(queryable, predicate, cancellationToken);
}
public static async Task<bool> AllAsync<T>(
public async static Task<bool> AllAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -59,7 +61,7 @@ public static class RepositoryAsyncExtensions
#region Count/LongCount
public static async Task<int> CountAsync<T>(
public async static Task<int> CountAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<int> CountAsync<T>(
public async static Task<int> CountAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -78,7 +80,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.CountAsync(queryable, predicate, cancellationToken);
}
public static async Task<long> LongCountAsync<T>(
public async static Task<long> LongCountAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<long> LongCountAsync<T>(
public async static Task<long> LongCountAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -101,41 +103,41 @@ public static class RepositoryAsyncExtensions
#region First/FirstOrDefault
public static async Task<T> FirstAsync<T>(
public async static Task<T> FirstAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T> FirstAsync<T>(
public async static Task<T> FirstAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> 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<T?> FirstOrDefaultAsync<T>(
public async static Task<T?> FirstOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T?> FirstOrDefaultAsync<T>(
public async static Task<T?> FirstOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> 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<T> LastAsync<T>(
public async static Task<T> LastAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T> LastAsync<T>(
public async static Task<T> LastAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> 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<T?> LastOrDefaultAsync<T>(
public async static Task<T?> LastOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T?> LastOrDefaultAsync<T>(
public async static Task<T?> LastOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> 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<T> AddOrderById<T>([NotNull] this IQueryable<T> queryable)
where T : class, IEntity
{
if (typeof(T).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntity<>)))
{
queryable = queryable.OrderBy(nameof(IEntity<object>.Id));
}
return queryable;
}
#endregion
#region Single/SingleOrDefault
public static async Task<T> SingleAsync<T>(
public async static Task<T> SingleAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T> SingleAsync<T>(
public async static Task<T> SingleAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -204,7 +220,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SingleAsync(queryable, predicate, cancellationToken);
}
public static async Task<T?> SingleOrDefaultAsync<T>(
public async static Task<T?> SingleOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T?> SingleOrDefaultAsync<T>(
public async static Task<T?> SingleOrDefaultAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
@ -227,7 +243,7 @@ public static class RepositoryAsyncExtensions
#region Min
public static async Task<T> MinAsync<T>(
public async static Task<T> MinAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<TResult> MinAsync<T, TResult>(
public async static Task<TResult> MinAsync<T, TResult>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default)
@ -250,7 +266,7 @@ public static class RepositoryAsyncExtensions
#region Max
public static async Task<T> MaxAsync<T>(
public async static Task<T> MaxAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<TResult> MaxAsync<T, TResult>(
public async static Task<TResult> MaxAsync<T, TResult>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default)
@ -273,7 +289,7 @@ public static class RepositoryAsyncExtensions
#region Sum
public static async Task<decimal> SumAsync<T>(
public async static Task<decimal> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default)
@ -283,7 +299,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<decimal?> SumAsync<T>(
public async static Task<decimal?> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default)
@ -293,7 +309,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<int> SumAsync<T>(
public async static Task<int> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default)
@ -303,7 +319,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<int?> SumAsync<T>(
public async static Task<int?> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default)
@ -313,7 +329,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<long> SumAsync<T>(
public async static Task<long> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default)
@ -323,7 +339,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<long?> SumAsync<T>(
public async static Task<long?> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default)
@ -333,7 +349,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<double> SumAsync<T>(
public async static Task<double> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default)
@ -343,7 +359,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<double?> SumAsync<T>(
public async static Task<double?> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default)
@ -353,7 +369,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<float> SumAsync<T>(
public async static Task<float> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, float>> selector,
CancellationToken cancellationToken = default)
@ -363,7 +379,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken);
}
public static async Task<float?> SumAsync<T>(
public async static Task<float?> SumAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default)
@ -377,7 +393,7 @@ public static class RepositoryAsyncExtensions
#region Average
public static async Task<decimal> AverageAsync<T>(
public async static Task<decimal> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default)
@ -387,7 +403,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<decimal?> AverageAsync<T>(
public async static Task<decimal?> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default)
@ -397,7 +413,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double> AverageAsync<T>(
public async static Task<double> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default)
@ -407,7 +423,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double?> AverageAsync<T>(
public async static Task<double?> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default)
@ -417,7 +433,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double> AverageAsync<T>(
public async static Task<double> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default)
@ -427,7 +443,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double?> AverageAsync<T>(
public async static Task<double?> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default)
@ -437,7 +453,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double> AverageAsync<T>(
public async static Task<double> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default)
@ -447,7 +463,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<double?> AverageAsync<T>(
public async static Task<double?> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default)
@ -457,7 +473,7 @@ public static class RepositoryAsyncExtensions
return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken);
}
public static async Task<float?> AverageAsync<T>(
public async static Task<float?> AverageAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default)
@ -471,7 +487,7 @@ public static class RepositoryAsyncExtensions
#region ToList/Array
public static async Task<List<T>> ToListAsync<T>(
public async static Task<List<T>> ToListAsync<T>(
[NotNull] this IReadOnlyRepository<T> 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<T[]> ToArrayAsync<T>(
public async static Task<T[]> ToArrayAsync<T>(
[NotNull] this IReadOnlyRepository<T> repository,
CancellationToken cancellationToken = default)
where T : class, IEntity

17
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<InvalidOperationException>(async () =>
await (await _personRepository.GetQueryableAsync()).LastOrDefaultAsync()
);
await uow.CompleteAsync();
}
}
}

Loading…
Cancel
Save