Browse Source

Resolved #3148: Add IRepository.GetAsync and IRepository.FindAsync methods those get predicate.

Also removed old & unused Get and Find methods from the EfCoreRepository.
pull/3151/head
Halil İbrahim Kalkan 6 years ago
parent
commit
f2be037bfc
  1. 16
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
  2. 34
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs
  3. 20
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs
  4. 33
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
  5. 8
      framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs
  6. 10
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  7. 5
      framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs
  8. 16
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs

16
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using JetBrains.Annotations;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
namespace Volo.Abp.Domain.Entities
{
@ -13,12 +11,24 @@ namespace Volo.Abp.Domain.Entities
/// </summary>
public static class EntityHelper
{
public static bool IsEntity([NotNull] Type type)
{
return typeof(IEntity).IsAssignableFrom(type);
}
public static bool IsEntityWithId([NotNull] Type type)
{
foreach (var interfaceType in type.GetInterfaces())
{
if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEntity<>))
{
return true;
}
}
return false;
}
public static bool HasDefaultId<TKey>(IEntity<TKey> entity)
{
if (EqualityComparer<TKey>.Default.Equals(entity.Id, default))

34
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs

@ -18,6 +18,34 @@ namespace Volo.Abp.Domain.Repositories
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>
where TEntity : class, IEntity
{
/// <summary>
/// Get a single entity by the given <paramref name="predicate"/>.
/// It returns null if no entity with the given <paramref name="predicate"/>.
/// It throws <see cref="InvalidOperationException"/> if there are multiple entities with the given <paramref name="predicate"/>.
/// </summary>
/// <param name="predicate">A condition to find the entity</param>
/// <param name="includeDetails">Set true to include all children of this entity</param>
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
Task<TEntity> FindAsync(
[NotNull] Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
/// <summary>
/// Get a single entity by the given <paramref name="predicate"/>.
/// It throws <see cref="EntityNotFoundException"/> if there is no entity with the given <paramref name="predicate"/>.
/// It throws <see cref="InvalidOperationException"/> if there are multiple entities with the given <paramref name="predicate"/>.
/// </summary>
/// <param name="predicate">A condition to filter entities</param>
/// <param name="includeDetails">Set true to include all children of this entity</param>
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
Task<TEntity> GetAsync(
[NotNull] Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
/// <summary>
/// Deletes many entities by function.
/// Notice that: All entities fits to given predicate are retrieved and deleted.
@ -30,7 +58,11 @@ namespace Volo.Abp.Domain.Repositories
/// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database.
/// </param>
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
Task DeleteAsync([NotNull] Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default);
Task DeleteAsync(
[NotNull] Expression<Func<TEntity, bool>> predicate,
bool autoSave = false,
CancellationToken cancellationToken = default
);
}
public interface IRepository<TEntity, TKey> : IRepository<TEntity>, IReadOnlyRepository<TEntity, TKey>, IBasicRepository<TEntity, TKey>

20
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs

@ -49,6 +49,26 @@ namespace Volo.Abp.Domain.Repositories
protected abstract IQueryable<TEntity> GetQueryable();
public abstract Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default);
public async Task<TEntity> GetAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(predicate, includeDetails, cancellationToken);
if (entity == null)
{
throw new EntityNotFoundException(typeof(TEntity));
}
return entity;
}
public abstract Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default);
protected virtual TQueryable ApplyDataFilters<TQueryable>(TQueryable query)

33
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

@ -93,6 +93,20 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return DbSet.AsQueryable();
}
public override async Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return includeDetails
? await WithDetails()
.Where(predicate)
.SingleOrDefaultAsync(GetCancellationToken(cancellationToken))
: await DbSet
.Where(predicate)
.SingleOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public override async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
var entities = await GetQueryable()
@ -173,18 +187,6 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
}
public virtual TEntity Get(TKey id, bool includeDetails = true)
{
var entity = Find(id, includeDetails);
if (entity == null)
{
throw new EntityNotFoundException(typeof(TEntity), id);
}
return entity;
}
public virtual async Task<TEntity> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, includeDetails, GetCancellationToken(cancellationToken));
@ -197,13 +199,6 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return entity;
}
public virtual TEntity Find(TKey id, bool includeDetails = true)
{
return includeDetails
? WithDetails().FirstOrDefault(e => e.Id.Equals(id))
: DbSet.Find(id);
}
public virtual async Task<TEntity> FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return includeDetails

8
framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs

@ -31,6 +31,14 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
return ApplyDataFilters(Collection.AsQueryable());
}
public override Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return Task.FromResult(Collection.AsQueryable().Where(predicate).SingleOrDefault());
}
public override Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
var entities = Collection.AsQueryable().Where(predicate).ToList();

10
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -169,6 +169,16 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
return GetMongoQueryable();
}
public override async Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(predicate)
.SingleOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual IMongoQueryable<TEntity> GetMongoQueryable()
{
return ApplyDataFilters(

5
framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs

@ -246,6 +246,11 @@ namespace Volo.Abp.Domain.Repositories
throw new NotImplementedException();
}
public override Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();

16
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs

@ -28,6 +28,14 @@ namespace Volo.Abp.TestApp.Testing
person.Phones.Count.ShouldBe(2);
}
[Fact]
public async Task GetAsync_With_Predicate()
{
var person = await PersonRepository.GetAsync(p => p.Name == "Douglas");
person.Name.ShouldBe("Douglas");
person.Phones.Count.ShouldBe(2);
}
[Fact]
public async Task FindAsync_Should_Return_Null_For_Not_Found_Entity()
{
@ -35,6 +43,14 @@ namespace Volo.Abp.TestApp.Testing
person.ShouldBeNull();
}
[Fact]
public async Task FindAsync_Should_Return_Null_For_Not_Found_Entity_With_Predicate()
{
var randomName = Guid.NewGuid().ToString();
var person = await PersonRepository.FindAsync(p => p.Name == randomName);
person.ShouldBeNull();
}
[Fact]
public async Task DeleteAsync()
{

Loading…
Cancel
Save