diff --git a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Dotnet5.GraphQL3.Repositories.Abstractions.csproj b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Dotnet5.GraphQL3.Repositories.Abstractions.csproj
index fb5cacb5..a73a7844 100644
--- a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Dotnet5.GraphQL3.Repositories.Abstractions.csproj
+++ b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Dotnet5.GraphQL3.Repositories.Abstractions.csproj
@@ -4,6 +4,7 @@
+
diff --git a/src/Dotnet5.GraphQL3.Repositories.Abstractions/IRepository.cs b/src/Dotnet5.GraphQL3.Repositories.Abstractions/IRepository.cs
index a765c9df..822c7f73 100644
--- a/src/Dotnet5.GraphQL3.Repositories.Abstractions/IRepository.cs
+++ b/src/Dotnet5.GraphQL3.Repositories.Abstractions/IRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
@@ -23,32 +24,37 @@ public interface IRepository
bool Exists(TId id);
Task ExistsAsync(TId id, CancellationToken cancellationToken = default);
- TEntity GetById(TId id, Func, IIncludableQueryable> include = default,
- bool asTracking = default);
-
- Task GetByIdAsync(TId id, CancellationToken cancellationToken,
- Func, IIncludableQueryable> include = default,
- bool asTracking = default);
+ TEntity GetById(TId id, Func, IIncludableQueryable> include = default, bool asTracking = default);
+ Task GetByIdAsync(TId id, CancellationToken cancellationToken, Func, IIncludableQueryable> include = default, bool asTracking = default);
void Update(TEntity entity);
Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
- PagedResult GetAll(
+ PaginatedResult GetAll(
PageParams pageParams,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
Func, IIncludableQueryable> include = default,
bool asTracking = default);
- PagedResult GetAllProjections(
+ PaginatedResult GetAllDynamically(
+ PageParams pageParams,
+ IEnumerable selected,
+ Func, List> mapping,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default);
+
+ PaginatedResult GetAllProjections(
PageParams pageParams,
Expression> selector = default,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
Func, IIncludableQueryable> include = default,
bool asTracking = default);
-
- Task> GetAllAsync(
+
+ Task> GetAllAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> predicate = default,
@@ -56,7 +62,16 @@ Task> GetAllAsync(
Func, IIncludableQueryable> include = default,
bool asTracking = default);
- Task> GetAllProjectionsAsync(
+ Task> GetAllDynamicallyAsync(
+ PageParams pageParams,
+ IEnumerable selected,
+ Func, List> mapping,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default);
+
+ Task> GetAllProjectionsAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> selector = default,
diff --git a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PagedResult.cs b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PagedResult.cs
deleted file mode 100644
index b97c498e..00000000
--- a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PagedResult.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.EntityFrameworkCore;
-
-namespace Dotnet5.GraphQL3.Repositories.Abstractions.Pages
-{
- public class PagedResult
- {
- private readonly int _index;
- private readonly IEnumerable _items;
- private readonly int _size;
-
- public PagedResult(IEnumerable items, int index, int size)
- {
- _items = items;
- _index = index;
- _size = size;
- }
-
- public IEnumerable Items
- => _items.Take(_size);
-
- public PageInfo PageInfo
- => new()
- {
- Current = _index,
- Size = Items.Count(),
- HasNext = _size < _items.Count(),
- HasPrevious = _index > 1
- };
-
- public static async Task> CreateAsync(IQueryable source, PageParams pageParams, CancellationToken cancellationToken)
- {
- pageParams ??= new();
- var items = await ApplyPagination(source, pageParams).ToListAsync(cancellationToken);
- return new PagedResult(items, pageParams.Index, pageParams.Size);
- }
-
- public static PagedResult Create(IQueryable source, PageParams pageParams)
- {
- pageParams ??= new();
- var items = ApplyPagination(source, pageParams).ToList();
- return new PagedResult(items, pageParams.Index, pageParams.Size);
- }
-
- private static IQueryable ApplyPagination(IQueryable source, PageParams pageParams)
- => source.Skip(pageParams.Size * (pageParams.Index - 1)).Take(pageParams.Size + 1);
- }
-}
\ No newline at end of file
diff --git a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PaginatedResult.cs b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PaginatedResult.cs
new file mode 100644
index 00000000..ee8c31b0
--- /dev/null
+++ b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Pages/PaginatedResult.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+
+namespace Dotnet5.GraphQL3.Repositories.Abstractions.Pages
+{
+ public class PaginatedResult
+ {
+ private readonly int _index;
+ private readonly IEnumerable _items;
+ private readonly int _size;
+
+ public PaginatedResult(IEnumerable items, int index, int size)
+ {
+ _items = items;
+ _index = index;
+ _size = size;
+ }
+
+ public IEnumerable Items
+ => _items.Take(_size);
+
+ public PageInfo PageInfo
+ => new()
+ {
+ Current = _index,
+ Size = Items.Count(),
+ HasNext = _size < _items.Count(),
+ HasPrevious = _index > 1
+ };
+
+ public static async Task> CreateDynamicallyAsync(IQueryable source, PageParams pageParams, Func, List> mapping)
+ {
+ pageParams ??= new();
+ var items = await ApplyPagination(source, pageParams).ToDynamicListAsync();
+ return new PaginatedResult(mapping(items), pageParams.Index, pageParams.Size);
+ }
+
+ public static PaginatedResult CreateDynamically(IQueryable source, PageParams pageParams, Func, List> mapping)
+ {
+ pageParams ??= new();
+ var items = ApplyPagination(source, pageParams).ToDynamicList();
+ return new PaginatedResult(mapping(items), pageParams.Index, pageParams.Size);
+ }
+
+ public static async Task> CreateAsync(IQueryable source, PageParams pageParams, CancellationToken cancellationToken)
+ {
+ pageParams ??= new();
+ var items = await ApplyPagination(source, pageParams).ToListAsync(cancellationToken);
+ return new PaginatedResult(items, pageParams.Index, pageParams.Size);
+ }
+
+ public static PaginatedResult Create(IQueryable source, PageParams pageParams)
+ {
+ pageParams ??= new();
+ var items = ApplyPagination(source, pageParams).ToList();
+ return new PaginatedResult(items, pageParams.Index, pageParams.Size);
+ }
+
+ private static IQueryable ApplyPagination(IQueryable source, PageParams pageParams)
+ => source.Skip(pageParams.Size * (pageParams.Index - 1)).Take(pageParams.Size + 1);
+
+ private static IQueryable ApplyPagination(IQueryable source, PageParams pageParams)
+ => source.Skip(pageParams.Size * (pageParams.Index - 1)).Take(pageParams.Size + 1);
+ }
+}
\ No newline at end of file
diff --git a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Repository.cs b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Repository.cs
index 5b442f96..f18d6ddc 100644
--- a/src/Dotnet5.GraphQL3.Repositories.Abstractions/Repository.cs
+++ b/src/Dotnet5.GraphQL3.Repositories.Abstractions/Repository.cs
@@ -1,6 +1,8 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
+using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
@@ -16,6 +18,8 @@ public abstract class Repository : IRepository
where TEntity : Entity
where TId : struct
{
+ private const string SelectorTemplate = "new({0})";
+
private readonly IConfigurationProvider _configuration;
private readonly DbSet _dbSet;
@@ -97,7 +101,7 @@ public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancella
_dbSet.Update(entity);
}
- public PagedResult GetAll(
+ public PaginatedResult GetAll(
PageParams pageParams,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
@@ -110,10 +114,10 @@ public PagedResult GetAll(
query = predicate is null ? query : query.Where(predicate);
query = orderBy is null ? query : orderBy(query);
- return PagedResult.Create(query, pageParams);
+ return PaginatedResult.Create(query, pageParams);
}
- public PagedResult GetAllProjections(
+ public PaginatedResult GetAllProjections(
PageParams pageParams,
Expression> selector = default,
Expression> predicate = default,
@@ -128,11 +132,31 @@ public PagedResult GetAllProjections(
query = orderBy is null ? query : orderBy(query);
return selector is null
- ? PagedResult.Create(_dbSet.ProjectTo(_configuration), pageParams)
- : PagedResult.Create(query.Select(selector), pageParams);
+ ? PaginatedResult.Create(_dbSet.ProjectTo(_configuration), pageParams)
+ : PaginatedResult.Create(query.Select(selector), pageParams);
}
+
+ public PaginatedResult GetAllDynamically(
+ PageParams pageParams,
+ IEnumerable selected,
+ Func, List> mapping,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default)
+ {
+ var query = asTracking ? _dbSet.AsTracking() : _dbSet.AsNoTrackingWithIdentityResolution();
- public Task> GetAllAsync(
+ query = include is null ? query : include(query);
+ query = predicate is null ? query : query.Where(predicate);
+ query = orderBy is null ? query : orderBy(query);
+
+ var selector = string.Format(SelectorTemplate, string.Join(',', selected));
+
+ return PaginatedResult.CreateDynamically(query.Select(selector), pageParams, mapping);
+ }
+
+ public Task> GetAllAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> predicate = default,
@@ -146,10 +170,30 @@ public Task> GetAllAsync(
query = predicate is null ? query : query.Where(predicate);
query = orderBy is null ? query : orderBy(query);
- return PagedResult.CreateAsync(query, pageParams, cancellationToken);
+ return PaginatedResult.CreateAsync(query, pageParams, cancellationToken);
+ }
+
+ public async Task> GetAllDynamicallyAsync(
+ PageParams pageParams,
+ IEnumerable selected,
+ Func, List> mapping,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default)
+ {
+ var query = asTracking ? _dbSet.AsTracking() : _dbSet.AsNoTrackingWithIdentityResolution();
+
+ query = include is null ? query : include(query);
+ query = predicate is null ? query : query.Where(predicate);
+ query = orderBy is null ? query : orderBy(query);
+
+ var selector = string.Format(SelectorTemplate, string.Join(',', selected));
+
+ return await PaginatedResult.CreateDynamicallyAsync(query.Select(selector), pageParams, mapping);
}
- public Task> GetAllProjectionsAsync(
+ public Task> GetAllProjectionsAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> selector = default,
@@ -165,8 +209,8 @@ public Task> GetAllProjectionsAsync(
query = orderBy is null ? query : orderBy(query);
return selector is null
- ? PagedResult.CreateAsync(_dbSet.ProjectTo(_configuration), pageParams, cancellationToken)
- : PagedResult.CreateAsync(query.Select(selector), pageParams, cancellationToken);
+ ? PaginatedResult.CreateAsync(_dbSet.ProjectTo(_configuration), pageParams, cancellationToken)
+ : PaginatedResult.CreateAsync(query.Select(selector), pageParams, cancellationToken);
}
}
}
\ No newline at end of file
diff --git a/src/Dotnet5.GraphQL3.Services.Abstractions/IService.cs b/src/Dotnet5.GraphQL3.Services.Abstractions/IService.cs
index 4f0d5d22..978ad16a 100644
--- a/src/Dotnet5.GraphQL3.Services.Abstractions/IService.cs
+++ b/src/Dotnet5.GraphQL3.Services.Abstractions/IService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
@@ -10,7 +11,7 @@
namespace Dotnet5.GraphQL3.Services.Abstractions
{
- public interface IService
+ public interface IService
where TEntity : Entity
where TModel : Model
where TId : struct
@@ -24,23 +25,37 @@ public interface IService
bool Exists(TId id);
Task ExistsAsync(TId id, CancellationToken cancellationToken);
+
+ TEntity GetById(TId id, Func, IIncludableQueryable> include = default, bool asTracking = default);
+ Task GetByIdAsync(TId id, CancellationToken cancellationToken, Func, IIncludableQueryable> include = default, bool asTracking = default);
- PagedResult GetAll(
- PageParams pageParams,
+ TEntity Save(TModel model);
+ Task SaveAsync(TModel model, CancellationToken cancellationToken);
+
+ PaginatedResult GetAll(
+ PageParams pageParams,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default);
+
+ PaginatedResult GetAllDynamically(
+ PageParams pageParams,
+ IEnumerable selected,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
- Func, IIncludableQueryable> include = default,
+ Func, IIncludableQueryable> include = default,
bool asTracking = default);
- PagedResult GetAllProjections(
+ PaginatedResult GetAllProjections(
PageParams pageParams,
Expression> selector = default,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
Func, IIncludableQueryable> include = default,
bool asTracking = default);
-
- Task> GetAllAsync(
+
+ Task> GetAllAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> predicate = default,
@@ -48,7 +63,15 @@ Task> GetAllAsync(
Func, IIncludableQueryable> include = default,
bool asTracking = default);
- Task> GetAllProjectionsAsync(
+ Task> GetAllDynamicallyAsync(
+ PageParams pageParams,
+ IEnumerable selected,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default);
+
+ Task> GetAllProjectionsAsync(
PageParams pageParams,
CancellationToken cancellationToken,
Expression> selector = default,
@@ -56,11 +79,5 @@ Task> GetAllProjectionsAsync(
Func, IOrderedQueryable> orderBy = default,
Func, IIncludableQueryable> include = default,
bool asTracking = default);
-
- TEntity GetById(TId id, Func, IIncludableQueryable> include = default, bool asTracking = default);
- Task GetByIdAsync(TId id, CancellationToken cancellationToken, Func, IIncludableQueryable> include = default, bool asTracking = default);
-
- TEntity Save(TModel model);
- Task SaveAsync(TModel model, CancellationToken cancellationToken);
}
}
\ No newline at end of file
diff --git a/src/Dotnet5.GraphQL3.Services.Abstractions/Models/Model.cs b/src/Dotnet5.GraphQL3.Services.Abstractions/Models/Model.cs
index c97ad127..8f7cef7d 100644
--- a/src/Dotnet5.GraphQL3.Services.Abstractions/Models/Model.cs
+++ b/src/Dotnet5.GraphQL3.Services.Abstractions/Models/Model.cs
@@ -1,8 +1,8 @@
namespace Dotnet5.GraphQL3.Services.Abstractions.Models
{
- public abstract record Model
+ public abstract class Model
where TId : struct
{
- private TId? Id { get; init; }
+ public TId? Id { get; init; }
}
}
\ No newline at end of file
diff --git a/src/Dotnet5.GraphQL3.Services.Abstractions/Service.cs b/src/Dotnet5.GraphQL3.Services.Abstractions/Service.cs
index a094badf..3b328715 100644
--- a/src/Dotnet5.GraphQL3.Services.Abstractions/Service.cs
+++ b/src/Dotnet5.GraphQL3.Services.Abstractions/Service.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
@@ -25,11 +26,7 @@ public abstract class Service : IService Repository;
protected readonly IUnitOfWork UnitOfWork;
- protected Service(
- IUnitOfWork unitOfWork,
- IRepository repository,
- IMapper mapper,
- INotificationContext notificationContext)
+ protected Service(IUnitOfWork unitOfWork, IRepository repository, IMapper mapper, INotificationContext notificationContext)
{
UnitOfWork = unitOfWork;
Repository = repository;
@@ -78,15 +75,24 @@ public virtual bool Exists(TId id)
public virtual async Task ExistsAsync(TId id, CancellationToken cancellationToken)
=> IsValid(id) ? await Repository.ExistsAsync(id, cancellationToken) : default;
- public virtual PagedResult GetAll(
+ public virtual PaginatedResult GetAll(
PageParams pageParams,
Expression> predicate = default,
Func, IOrderedQueryable> orderBy = default,
Func, IIncludableQueryable> include = default,
bool asTracking = default)
=> Repository.GetAll(pageParams, predicate, orderBy, include, asTracking);
-
- public virtual PagedResult GetAllProjections(
+
+ public virtual PaginatedResult GetAllDynamically(
+ PageParams pageParams,
+ IEnumerable selected,
+ Expression> predicate = default,
+ Func, IOrderedQueryable> orderBy = default,
+ Func, IIncludableQueryable> include = default,
+ bool asTracking = default)
+ => Repository.GetAllDynamically(pageParams, selected, list => Mapper.Map>(list), predicate, orderBy, include, asTracking);
+
+ public virtual PaginatedResult GetAllProjections(
PageParams pageParams,
Expression