From fcaa050af25f565bd2d6d73afb65c13212b22e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 12 Dec 2016 00:07:16 +0300 Subject: [PATCH] Implement IQueryable for IQueryableRepository --- .../Tickets/Dtos/GetAllTicketsInput.cs | 7 ++ .../AbpDesk/Tickets/ITicketAppService.cs | 2 +- .../AbpDesk/Tickets/TicketAppService.cs | 14 ++-- .../AbpDesk/ConsoleDemo/TicketLister.cs | 3 +- .../Controllers/TicketsController.cs | 5 +- .../Services/Dtos/ILimitedResultRequest.cs | 13 ++++ .../Services/Dtos/IPagedResultRequest.cs | 13 ++++ .../AbpEfCoreServiceCollectionExtensions.cs | 3 + .../EfCoreRepositoryExtensions.cs | 35 ++++++++++ .../EntityFrameworkCore/EfCoreRepository.cs | 36 ++++------ .../EntityFrameworkCore/IEfCoreRepository.cs | 16 +++++ src/Volo.Abp.TestBase/AbpIntegratedTest.cs | 1 - .../Repositories/IQueryableRepository.cs | 49 +------------ .../Abp/Domain/Repositories/IRepository.cs | 11 ++- .../Domain/Repositories/IRepositoryMarker.cs | 7 -- .../Repositories/QueryableRepositoryBase.cs | 41 ++++------- .../Abp/Domain/Repositories/RepositoryBase.cs | 10 +-- .../Linq/Extensions/QueryableExtensions.cs | 68 +++++++++++++++++++ src/Volo.Abp/project.json | 3 +- .../AbpDesk/AbpDeskApplicationTestModule.cs | 6 +- .../AbpDesk/Tickets/TicketAppService_Tests.cs | 17 ++++- 21 files changed, 230 insertions(+), 130 deletions(-) create mode 100644 src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/Dtos/GetAllTicketsInput.cs create mode 100644 src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/ILimitedResultRequest.cs create mode 100644 src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/IPagedResultRequest.cs create mode 100644 src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EfCoreRepositoryExtensions.cs create mode 100644 src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/IEfCoreRepository.cs delete mode 100644 src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepositoryMarker.cs create mode 100644 src/Volo.Abp/Volo/Abp/Linq/Extensions/QueryableExtensions.cs diff --git a/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/Dtos/GetAllTicketsInput.cs b/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/Dtos/GetAllTicketsInput.cs new file mode 100644 index 0000000000..6407fe39b7 --- /dev/null +++ b/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/Dtos/GetAllTicketsInput.cs @@ -0,0 +1,7 @@ +namespace AbpDesk.Tickets.Dtos +{ + public class GetAllTicketsInput + { + public string Filter { get; set; } + } +} \ No newline at end of file diff --git a/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/ITicketAppService.cs b/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/ITicketAppService.cs index b01a1e3fe2..3f3824bb9b 100644 --- a/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/ITicketAppService.cs +++ b/src/AbpDesk/AbpDesk.Application.Contracts/AbpDesk/Tickets/ITicketAppService.cs @@ -6,6 +6,6 @@ namespace AbpDesk.Tickets { public interface ITicketAppService : IApplicationService { - ListResultDto GetAll(); + ListResultDto GetAll(GetAllTicketsInput input); } } diff --git a/src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs b/src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs index 8c1eaf8b06..e51402d435 100644 --- a/src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs +++ b/src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs @@ -2,23 +2,27 @@ using AbpDesk.Tickets.Dtos; using Volo.Abp.Application.Services.Dtos; using Volo.Abp.Domain.Repositories; +using Volo.Abp.Linq.Extensions; +using Volo.ExtensionMethods; namespace AbpDesk.Tickets { public class TicketAppService : ITicketAppService { - private readonly IRepository _ticketRepository; + private readonly IQueryableRepository _ticketRepository; - public TicketAppService(IRepository ticketRepository) + public TicketAppService(IQueryableRepository ticketRepository) { _ticketRepository = ticketRepository; } - public ListResultDto GetAll() + public ListResultDto GetAll(GetAllTicketsInput input) { var tickets = _ticketRepository - .GetList() - .Select(t => new TicketDto { Id = t.Id, Title = t.Title, Body = t.Body }) + .WhereIf( + !input.Filter.IsNullOrWhiteSpace(), + t => t.Title.Contains(input.Filter) || t.Body.Contains(input.Filter) + ).Select(t => new TicketDto { Id = t.Id, Title = t.Title, Body = t.Body }) .ToList(); return new ListResultDto(tickets); diff --git a/src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs b/src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs index f2c7a5ccff..b616915f51 100644 --- a/src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs +++ b/src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs @@ -1,5 +1,6 @@ using System; using AbpDesk.Tickets; +using AbpDesk.Tickets.Dtos; using Volo.DependencyInjection; namespace AbpDesk.ConsoleDemo @@ -15,7 +16,7 @@ namespace AbpDesk.ConsoleDemo public void List() { - var result = _ticketAppService.GetAll(); + var result = _ticketAppService.GetAll(new GetAllTicketsInput()); foreach (var ticket in result.Items) { diff --git a/src/AbpDesk/AbpDesk.UI/Controllers/TicketsController.cs b/src/AbpDesk/AbpDesk.UI/Controllers/TicketsController.cs index 613b9e5355..8d7ee64962 100644 --- a/src/AbpDesk/AbpDesk.UI/Controllers/TicketsController.cs +++ b/src/AbpDesk/AbpDesk.UI/Controllers/TicketsController.cs @@ -1,5 +1,6 @@ using AbpDesk.Models.Tickets; using AbpDesk.Tickets; +using AbpDesk.Tickets.Dtos; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; @@ -14,9 +15,9 @@ namespace AbpDesk.Controllers _ticketAppService = ticketAppService; } - public IActionResult Index() + public IActionResult Index(GetAllTicketsInput input) { - var result = _ticketAppService.GetAll(); + var result = _ticketAppService.GetAll(input); var model = new IndexViewModel { diff --git a/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/ILimitedResultRequest.cs b/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/ILimitedResultRequest.cs new file mode 100644 index 0000000000..5027f18c1a --- /dev/null +++ b/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/ILimitedResultRequest.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.Application.Services.Dtos +{ + /// + /// This interface is defined to standardize to request a limited result. + /// + public interface ILimitedResultRequest + { + /// + /// Max expected result count. + /// + int MaxResultCount { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/IPagedResultRequest.cs b/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/IPagedResultRequest.cs new file mode 100644 index 0000000000..02abd640c9 --- /dev/null +++ b/src/Volo.Abp.ApplicationContracts/Volo/Abp/Application/Services/Dtos/IPagedResultRequest.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.Application.Services.Dtos +{ + /// + /// This interface is defined to standardize to request a paged result. + /// + public interface IPagedResultRequest : ILimitedResultRequest + { + /// + /// Skip count (beginning of the page). + /// + int SkipCount { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs index ad759e16fe..0d043cd71a 100644 --- a/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs +++ b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs @@ -18,10 +18,13 @@ namespace Microsoft.Extensions.DependencyInjection foreach (var entityType in DbContextHelper.GetEntityTypes(dbContextType)) { var primaryKeyType = EntityHelper.GetPrimaryKeyType(entityType); + var repositoryInterfaceType = typeof(IRepository<,>).MakeGenericType(entityType, primaryKeyType); + var queryableRepositoryInterfaceType = typeof(IQueryableRepository<,>).MakeGenericType(entityType, primaryKeyType); var repositoryImplementationType = typeof(EfCoreRepository<,,>).MakeGenericType(dbContextType, entityType, primaryKeyType); services.TryAddTransient(repositoryInterfaceType, repositoryImplementationType); + services.TryAddTransient(queryableRepositoryInterfaceType, repositoryImplementationType); } return services; diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EfCoreRepositoryExtensions.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EfCoreRepositoryExtensions.cs new file mode 100644 index 0000000000..e7f14c51d8 --- /dev/null +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EfCoreRepositoryExtensions.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Repositories.EntityFrameworkCore; + +namespace Volo.Abp.Repositories +{ + public static class EfCoreRepositoryExtensions + { + public static DbContext GetDbContext(this IRepository repository) + where TEntity : class, IEntity, new() + { + var efCoreRepository = repository as IEfCoreRepository; + if (efCoreRepository == null) + { + throw new ArgumentException("Given repository does not implement " + typeof(IEfCoreRepository).AssemblyQualifiedName, nameof(repository)); + } + + return efCoreRepository.DbContext; + } + + public static DbSet GetDbSet(this IRepository repository) + where TEntity : class, IEntity, new() + { + var efCoreRepository = repository as IEfCoreRepository; + if (efCoreRepository == null) + { + throw new ArgumentException("Given repository does not implement " + typeof(IEfCoreRepository).AssemblyQualifiedName, nameof(repository)); + } + + return efCoreRepository.DbSet; + } + } +} diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 4ddf2a0c18..04c342defa 100644 --- a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Entities; @@ -10,24 +8,24 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.Repositories.EntityFrameworkCore { - //TODO: Override async versions and others - - public class EfCoreRepository : QueryableRepositoryBase + public class EfCoreRepository : QueryableRepositoryBase, IEfCoreRepository where TDbContext : AbpDbContext where TEntity : class, IEntity { - protected virtual TDbContext DbContext { get; } - - protected virtual DbSet DbSet => DbContext.Set(); + public virtual TDbContext DbContext { get; } + public virtual DbSet DbSet => DbContext.Set(); + + DbContext IEfCoreRepository.DbContext => DbContext; + public EfCoreRepository(TDbContext dbContext) { DbContext = dbContext; } - public override IQueryable GetQueryable() + protected override IQueryable GetQueryable() { - return DbSet; + return DbSet.AsQueryable(); } public override Task> GetListAsync() @@ -37,7 +35,7 @@ namespace Volo.Abp.Repositories.EntityFrameworkCore public override async Task GetAsync(TPrimaryKey id) { - var entity = await FirstOrDefaultAsync(id); + var entity = await FindAsync(id); if (entity == null) { throw new EntityNotFoundException(typeof(TEntity), id); @@ -46,21 +44,16 @@ namespace Volo.Abp.Repositories.EntityFrameworkCore return entity; } - public override TEntity FirstOrDefault(TPrimaryKey id) + public override TEntity Find(TPrimaryKey id) { return DbSet.Find(id); } - public override Task FirstOrDefaultAsync(TPrimaryKey id) + public override Task FindAsync(TPrimaryKey id) { return DbSet.FindAsync(id); } - public override Task FirstOrDefaultAsync(Expression> predicate) - { - return GetQueryable().FirstOrDefaultAsync(predicate); - } - public override TEntity Insert(TEntity entity) { return DbSet.Add(entity).Entity; @@ -94,10 +87,5 @@ namespace Volo.Abp.Repositories.EntityFrameworkCore { return DbSet.CountAsync(); } - - public override Task CountAsync(Expression> predicate) - { - return DbSet.CountAsync(predicate); - } } } diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/IEfCoreRepository.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/IEfCoreRepository.cs new file mode 100644 index 0000000000..684512d1d0 --- /dev/null +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/IEfCoreRepository.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.Repositories.EntityFrameworkCore +{ + public interface IEfCoreRepository + { + DbContext DbContext { get; } + } + + public interface IEfCoreRepository : IEfCoreRepository + where TEntity : class, IEntity + { + DbSet DbSet { get; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.TestBase/AbpIntegratedTest.cs b/src/Volo.Abp.TestBase/AbpIntegratedTest.cs index 8abd66c0dd..41fa62589e 100644 --- a/src/Volo.Abp.TestBase/AbpIntegratedTest.cs +++ b/src/Volo.Abp.TestBase/AbpIntegratedTest.cs @@ -7,7 +7,6 @@ namespace Volo.Abp.TestBase public class AbpIntegratedTest : IDisposable where TStartupModule : IAbpModule { - protected AbpApplication Application { get; } protected IServiceProvider ServiceProvider => Application.ServiceProvider; diff --git a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IQueryableRepository.cs b/src/Volo.Abp/Volo/Abp/Domain/Repositories/IQueryableRepository.cs index 5e20db10bb..80f713208e 100644 --- a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IQueryableRepository.cs +++ b/src/Volo.Abp/Volo/Abp/Domain/Repositories/IQueryableRepository.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -7,41 +6,9 @@ using Volo.Abp.Domain.Entities; namespace Volo.Abp.Domain.Repositories { - public interface IQueryableRepository : IRepository + public interface IQueryableRepository : IRepository, IQueryable where TEntity : class, IEntity { - /// - /// Used to get a IQueryable that is used to retrieve entities from entire table. - /// - /// IQueryable to be used to select entities from database - IQueryable GetQueryable(); - - /// - /// Used to get all entities based on given . - /// - /// A condition to filter entities - /// List of all entities - List GetList(Expression> predicate); - - /// - /// Used to get all entities based on given . - /// - /// A condition to filter entities - /// List of all entities - Task> GetListAsync(Expression> predicate); - - /// - /// Gets an entity with given given predicate or null if not found. - /// - /// Predicate to filter entities - TEntity FirstOrDefault(Expression> predicate); - - /// - /// Gets an entity with given given predicate or null if not found. - /// - /// Predicate to filter entities - Task FirstOrDefaultAsync(Expression> predicate); - /// /// Deletes many entities by function. /// Notice that: All entities fits to given predicate are retrieved and deleted. @@ -59,19 +26,5 @@ namespace Volo.Abp.Domain.Repositories /// /// A condition to filter entities Task DeleteAsync(Expression> predicate); - - /// - /// Gets count of all entities in this repository based on given . - /// - /// A method to filter count - /// Count of entities - int Count(Expression> predicate); - - /// - /// Gets count of all entities in this repository based on given . - /// - /// A method to filter count - /// Count of entities - Task CountAsync(Expression> predicate); } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepository.cs b/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepository.cs index 85f1fbda6b..8f37a50d4c 100644 --- a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepository.cs +++ b/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepository.cs @@ -7,7 +7,12 @@ namespace Volo.Abp.Domain.Repositories { //TODO: Didn't get all members from ABP 1.x - public interface IRepository : IRepositoryMarker, ITransientDependency + public interface IRepository : ITransientDependency + { + + } + + public interface IRepository : IRepository where TEntity : class, IEntity { /// @@ -41,14 +46,14 @@ namespace Volo.Abp.Domain.Repositories /// /// Primary key of the entity to get /// Entity or null - TEntity FirstOrDefault(TPrimaryKey id); + TEntity Find(TPrimaryKey id); /// /// Gets an entity with given primary key or null if not found. /// /// Primary key of the entity to get /// Entity or null - Task FirstOrDefaultAsync(TPrimaryKey id); + Task FindAsync(TPrimaryKey id); /// /// Inserts a new entity. diff --git a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepositoryMarker.cs b/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepositoryMarker.cs deleted file mode 100644 index 31805807b0..0000000000 --- a/src/Volo.Abp/Volo/Abp/Domain/Repositories/IRepositoryMarker.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Abp.Domain.Repositories -{ - public interface IRepositoryMarker - { - - } -} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Domain/Repositories/QueryableRepositoryBase.cs b/src/Volo.Abp/Volo/Abp/Domain/Repositories/QueryableRepositoryBase.cs index a337602e5e..74d77c7d05 100644 --- a/src/Volo.Abp/Volo/Abp/Domain/Repositories/QueryableRepositoryBase.cs +++ b/src/Volo.Abp/Volo/Abp/Domain/Repositories/QueryableRepositoryBase.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; @@ -10,36 +11,32 @@ namespace Volo.Abp.Domain.Repositories public abstract class QueryableRepositoryBase : RepositoryBase, IQueryableRepository where TEntity : class, IEntity { - public abstract IQueryable GetQueryable(); + public virtual Type ElementType => GetQueryable().ElementType; - public override List GetList() - { - return GetQueryable().ToList(); - } + public virtual Expression Expression => GetQueryable().Expression; - public virtual List GetList(Expression> predicate) - { - return GetQueryable().Where(predicate).ToList(); - } + public virtual IQueryProvider Provider => GetQueryable().Provider; - public virtual Task> GetListAsync(Expression> predicate) + IEnumerator IEnumerable.GetEnumerator() { - return Task.FromResult(GetList(predicate)); + return GetEnumerator(); } - public override TEntity FirstOrDefault(TPrimaryKey id) + public IEnumerator GetEnumerator() { - return FirstOrDefault(CreateEqualityExpressionForId(id)); + return GetQueryable().GetEnumerator(); } - public virtual TEntity FirstOrDefault(Expression> predicate) + protected abstract IQueryable GetQueryable(); + + public override List GetList() { - return GetQueryable().FirstOrDefault(predicate); + return GetQueryable().ToList(); } - public virtual Task FirstOrDefaultAsync(Expression> predicate) + public override TEntity Find(TPrimaryKey id) { - return Task.FromResult(FirstOrDefault(predicate)); + return GetQueryable().FirstOrDefault(CreateEqualityExpressionForId(id)); } public virtual void Delete(Expression> predicate) @@ -60,15 +57,5 @@ namespace Volo.Abp.Domain.Repositories { return GetQueryable().Count(); } - - public virtual int Count(Expression> predicate) - { - return GetQueryable().Count(predicate); - } - - public virtual Task CountAsync(Expression> predicate) - { - return Task.FromResult(Count(predicate)); - } } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Domain/Repositories/RepositoryBase.cs b/src/Volo.Abp/Volo/Abp/Domain/Repositories/RepositoryBase.cs index af24a4fc0a..a35a7ce179 100644 --- a/src/Volo.Abp/Volo/Abp/Domain/Repositories/RepositoryBase.cs +++ b/src/Volo.Abp/Volo/Abp/Domain/Repositories/RepositoryBase.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Domain.Repositories public virtual TEntity Get(TPrimaryKey id) { - var entity = FirstOrDefault(id); + var entity = Find(id); if (entity == null) { throw new EntityNotFoundException(typeof(TEntity), id); @@ -32,11 +32,11 @@ namespace Volo.Abp.Domain.Repositories return Task.FromResult(Get(id)); } - public abstract TEntity FirstOrDefault(TPrimaryKey id); + public abstract TEntity Find(TPrimaryKey id); - public virtual Task FirstOrDefaultAsync(TPrimaryKey id) + public virtual Task FindAsync(TPrimaryKey id) { - return Task.FromResult(FirstOrDefault(id)); + return Task.FromResult(Find(id)); } public abstract TEntity Insert(TEntity entity); @@ -73,7 +73,7 @@ namespace Volo.Abp.Domain.Repositories public virtual void Delete(TPrimaryKey id) { - var entity = FirstOrDefault(id); + var entity = Find(id); if (entity == null) { return; diff --git a/src/Volo.Abp/Volo/Abp/Linq/Extensions/QueryableExtensions.cs b/src/Volo.Abp/Volo/Abp/Linq/Extensions/QueryableExtensions.cs new file mode 100644 index 0000000000..c824c6eae1 --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Linq/Extensions/QueryableExtensions.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using JetBrains.Annotations; +using Volo.Abp.Application.Services.Dtos; + +namespace Volo.Abp.Linq.Extensions +{ + /// + /// Some useful extension methods for . + /// + public static class QueryableExtensions + { + /// + /// Used for paging. Can be used as an alternative to Skip(...).Take(...) chaining. + /// + public static IQueryable PageBy([NotNull] this IQueryable query, int skipCount, int maxResultCount) + { + Check.NotNull(query, nameof(query)); + + return query.Skip(skipCount).Take(maxResultCount); + } + + /// + /// Used for paging with an object. + /// + /// Queryable to apply paging + /// An object implements interface + public static IQueryable PageBy([NotNull] this IQueryable query, IPagedResultRequest pagedResultRequest) + { + Check.NotNull(query, nameof(query)); + + return query.PageBy(pagedResultRequest.SkipCount, pagedResultRequest.MaxResultCount); + } + + /// + /// Filters a by given predicate if given condition is true. + /// + /// Queryable to apply filtering + /// A boolean value + /// Predicate to filter the query + /// Filtered or not filtered query based on + public static IQueryable WhereIf([NotNull] this IQueryable query, bool condition, Expression> predicate) + { + Check.NotNull(query, nameof(query)); + + return condition + ? query.Where(predicate) + : query; + } + + /// + /// Filters a by given predicate if given condition is true. + /// + /// Queryable to apply filtering + /// A boolean value + /// Predicate to filter the query + /// Filtered or not filtered query based on + public static IQueryable WhereIf([NotNull] this IQueryable query, bool condition, Expression> predicate) + { + Check.NotNull(query, nameof(query)); + + return condition + ? query.Where(predicate) + : query; + } + } +} diff --git a/src/Volo.Abp/project.json b/src/Volo.Abp/project.json index 7da01df4ed..69460a711e 100644 --- a/src/Volo.Abp/project.json +++ b/src/Volo.Abp/project.json @@ -9,7 +9,8 @@ "Newtonsoft.Json": "9.0.1", "Nito.AsyncEx.Context": "1.1.0", "System.Runtime.Loader": "4.3.0", - "System.Linq.Queryable": "4.3.0" + "System.Linq.Queryable": "4.3.0", + "Volo.Abp.ApplicationContracts": "1.0.0-*" }, "frameworks": { diff --git a/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/AbpDeskApplicationTestModule.cs b/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/AbpDeskApplicationTestModule.cs index 31f153b315..f27c3002ba 100644 --- a/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/AbpDeskApplicationTestModule.cs +++ b/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/AbpDeskApplicationTestModule.cs @@ -1,4 +1,5 @@ -using AbpDesk.EntityFrameworkCore; +using System; +using AbpDesk.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; @@ -11,10 +12,9 @@ namespace AbpDesk public override void ConfigureServices(IServiceCollection services) { services.AddEntityFrameworkInMemoryDatabase(); - services.AddDbContext(options => { - options.UseInMemoryDatabase(); + options.UseInMemoryDatabase(Guid.NewGuid().ToString()); }); } } diff --git a/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/Tickets/TicketAppService_Tests.cs b/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/Tickets/TicketAppService_Tests.cs index b2c2896128..44b0cc0a96 100644 --- a/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/Tickets/TicketAppService_Tests.cs +++ b/test/AbpDesk/AbpDesk.Application.Tests/AbpDesk/Tickets/TicketAppService_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using AbpDesk.Tickets.Dtos; +using Microsoft.Extensions.DependencyInjection; using Shouldly; using Xunit; @@ -18,11 +19,23 @@ namespace AbpDesk.Tickets { //Act - var result = _ticketAppService.GetAll(); + var result = _ticketAppService.GetAll(new GetAllTicketsInput()); //Assert result.Items.Count.ShouldBe(1); } + + [Fact] + public void GetAll_Filtered_Test() + { + //Act + + var result = _ticketAppService.GetAll(new GetAllTicketsInput { Filter = "non-existing-text" }); + + //Assert + + result.Items.Count.ShouldBe(0); + } } }