This commit is contained in:
2026-05-04 00:37:06 +03:30
parent 37e537f385
commit fcf02c9b7b
21 changed files with 5640 additions and 2748 deletions
+745
View File
@@ -0,0 +1,745 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.EntityFrameworkCore.Query;
using xCommons.Extensions;
using xDataService.Interfaces;
using xModels.Base;
using xModels.Dtos;
namespace xDataService.Providers
{
/// <summary>
/// a Base Repository Service Implementation which Use a Repository Patterns Implementatin
/// and provides Data Manipulation Methods using Dtos instead of Entities ...
///
/// it can be use of following Repository Patterns Implementation:
/// <see cref="XBaseEFRepository"/>>
/// <see cref="XBaseMongoRepository"/>>
/// <see cref="XBaseInMemoryRepository"/>>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDto"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class XBaseRepositoryService<TEntity, TDto, TKey> : IXBaseRepositoryService<TEntity, TDto, TKey>
where TEntity : XBaseEntity<TKey>
where TDto : XBaseEntityDto<TKey>
{
//
#region Properties ...
/// <summary>
/// Mapper Instance ...
/// </summary>
public IMapper Mapper { get; }
/// <summary>
/// Repository Implementation for Data Manipulations ...
/// </summary>
public IXBaseRepository<TEntity, TKey> Repository { get; }
/// <summary>
/// Mapping Profile Configuration ...
///
/// this Configuration used for Mapping TEntity to Dto and reverse ...
/// default mapping prepared on Constructing time, other custom maps
/// must handled manually if required ...
/// </summary>
public MapperConfiguration MapperConfiguration { get; }
#endregion
//
#region Constructor ...
public XBaseRepositoryService(
IXBaseRepository<TEntity, TKey> repository,
IEnumerable<Profile> mapperProfiles = null
)
{
//
Repository = repository;
//
// Preparing Mapping Configurations ...
MapperConfiguration = new MapperConfiguration(cfg =>
{
//
// Add Default Profiles ...
//
// Entity To Dto ...
cfg.CreateMap<TEntity, TDto>()
.ForMember(dest => dest.Deleted, opt => opt.Ignore());
//
// Dto to Entity ...
cfg.CreateMap<TDto, TEntity>()
.ForMember(dest => dest.Deleted, opt => opt.Ignore());
//
// Add Provided Profiles if Provided ...
// if Same Profiles Provided, here resolved ...
if (!mapperProfiles.IsNull() &&
mapperProfiles.HasChild())
{
cfg.AddProfiles(mapperProfiles);
}
});
//
// Make Mapper Instance using prepared Configuration ...
Mapper = MapperConfiguration.CreateMapper();
}
#endregion
//
#region Actions ...
//
#region Add ...
/// <summary>
/// add a new Dto ...
/// </summary>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> AddAsync(
TDto item,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
// Validate ...
bool isValid = !item.IsNull();
if (!isValid)
{
return result;
}
//
try
{
//
var entity = Mapper.Map<TEntity>(item);
//
entity = await Repository.AddAsync(
item: entity,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// add or update a Dto (add if not exists/update if exists) ...
/// </summary>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> AddOrUpdateAsync(
TDto item,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
// Validate ...
bool isValid = !item.IsNull();
if (!isValid)
{
return result;
}
//
try
{
//
var entity = Mapper.Map<TEntity>(item);
//
entity = await Repository.AddOrUpdateAsync(
item: entity,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// add a range of new Dtos ...
/// </summary>
/// <param name="items"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task AddRangeAsync(
IEnumerable<TDto> items,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
// Validate ...
bool isValid =
!items.IsNull() &&
items.HasChild();
if (!isValid)
{
return;
}
//
try
{
//
var entities = Mapper.Map<IEnumerable<TEntity>>(items);
//
await Repository.AddRangeAsync(
items: entities,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
}
catch
{ }
}
#endregion
//
#region Update ...
/// <summary>
/// Update an Dto values ...
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> UpdateAsync(
TKey id,
TDto item,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
try
{
//
var entity = Mapper.Map<TEntity>(item);
//
entity = await Repository.UpdateAsync(
id: item.Id,
item: entity,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// Update a range of Dtos ...
/// </summary>
/// <param name="items"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<bool> UpdateRangeAsync(
IEnumerable<TDto> items,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
var result =
!items.IsNull() &&
items.HasChild();
if (!result)
{
return result;
}
//
try
{
//
var entitis = Mapper.Map<IEnumerable<TEntity>>(items);
//
result = await Repository.UpdateRangeAsync(
items: entitis,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
}
catch
{
result = false;
}
//
return result;
}
#endregion
//
#region Remove ...
/// <summary>
/// remove an Dto by it's Id ...
/// </summary>
/// <param name="id"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> RemoveAsync(
TKey id,
bool softDelete = true,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
try
{
//
var entity = await Repository.RemoveAsync(
id: id,
softDelete: softDelete,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// remove an Dto ...
/// </summary>
/// <param name="item"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> RemoveAsync(
TDto item,
bool softDelete = true,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
try
{
//
var entity = Mapper.Map<TEntity>(item);
//
entity = await Repository.RemoveAsync(
item: entity,
softDelete: softDelete,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// remove a range of exists Dtos ...
/// </summary>
/// <param name="items"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task RemoveRangeAsync(
IEnumerable<TDto> items,
bool softDelete = true,
bool saveChanges = true,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
var isValid =
!items.IsNull() &&
items.HasChild();
if (!isValid)
{
return;
}
//
var entities = Mapper.Map<IEnumerable<TEntity>>(items);
//
try
{
//
await Repository.RemoveRangeAsync(
items: entities,
softDelete: softDelete,
saveChanges: saveChanges,
cancellationToken: cancellationToken
);
}
catch
{ }
}
#endregion
//
#region Count ...
/// <summary>
/// count all exists Dtos ...
/// </summary>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<int> CountAsync(
bool ignoreSoftDeleteds = true,
CancellationToken cancellationToken = default
)
{
//
var result = await Repository.CountAsync(
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
return result;
}
/// <summary>
/// count all exists Entities Pages by providing page size ...
/// </summary>
/// <param name="pageSize"></param>
/// <param name="totalItems"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<int> PagesCountAsync(
int pageSize,
int? totalItems = null,
bool ignoreSoftDeleteds = true,
CancellationToken cancellationToken = default
)
{
//
var result = await Repository.PagesCountAsync(
pageSize: pageSize,
totalItems: totalItems,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
return result;
}
#endregion
//
#region Exists ...
/// <summary>
/// Check a Dto exists or not ...
/// </summary>
/// <param name="id"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<bool> IsExistsAsync(
TKey id,
bool ignoreSoftDeleteds = true,
CancellationToken cancellationToken = default
)
{
//
var result = await Repository.IsExistsAsync(
id: id,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
return result;
}
#endregion
//
#region Retrieve ...
/// <summary>
/// retrieve an Dto by it's Id ...
/// </summary>
/// <param name="id"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="includeBuilder"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> GetAsync(
TKey id,
bool ignoreSoftDeleteds = true,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> includeBuilder = null,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
try
{
//
var entity = await Repository.GetAsync(
id: id,
includeBuilder: includeBuilder,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// retrieve all exists Dtos ...
/// </summary>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="orderBuilder"></param>
/// <param name="includeBuilder"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<IEnumerable<TDto>> GetAllAsync(
bool ignoreSoftDeleteds = true,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBuilder = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> includeBuilder = null,
CancellationToken cancellationToken = default
)
{
//
IEnumerable<TDto> result = Enumerable.Empty<TDto>();
//
try
{
//
var entities = await Repository.GetAllAsync(
orderBuilder: orderBuilder,
includeBuilder: includeBuilder,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
result = Mapper.Map<IEnumerable<TDto>>(entities);
}
catch
{ }
//
return result;
}
/// <summary>
/// find an Dto by providing a Conditional Expression ...
/// </summary>
/// <param name="predicate"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="includeBuilder"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<TDto> FindOneAsync(
Expression<Func<TEntity, bool>> predicate,
bool ignoreSoftDeleteds = true,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> includeBuilder = null,
CancellationToken cancellationToken = default
)
{
//
TDto result = null;
//
try
{
//
var entity = await Repository.FindOneAsync(
predicate: predicate,
includeBuilder: includeBuilder,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
result = Mapper.Map<TDto>(entity);
}
catch
{ }
//
return result;
}
/// <summary>
/// find a collection of Dtos by proving a Conditional Expression ...
/// </summary>
/// <param name="predicate"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="orderBuilder"></param>
/// <param name="includeBuilder"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<IEnumerable<TDto>> FindManyAsync(
Expression<Func<TEntity, bool>> predicate,
bool ignoreSoftDeleteds = true,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBuilder = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> includeBuilder = null,
CancellationToken cancellationToken = default
)
{
//
IEnumerable<TDto> result = Enumerable.Empty<TDto>();
//
try
{
//
var entities = await Repository.FindManyAsync(
predicate: predicate,
orderBuilder: orderBuilder,
includeBuilder: includeBuilder,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
result = Mapper.Map<IEnumerable<TDto>>(entities);
}
catch
{ }
//
return result;
}
/// <summary>
/// retrieve Dtos based on XQuery Pagination structure ...
/// </summary>
/// <param name="query"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="predicate"></param>
/// <param name="orderBuilder"></param>
/// <param name="includeBuilder"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<XQueryResult<TDto>> QueryAsync(
XQuery query,
bool ignoreSoftDeleteds = true,
Expression<Func<TEntity, bool>> predicate = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBuilder = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> includeBuilder = null,
CancellationToken cancellationToken = default
)
{
//
XQueryResult<TDto> result = null;
//
try
{
//
var entityResult = await Repository.QueryAsync(
query: query,
predicate: predicate,
orderBuilder: orderBuilder,
includeBuilder: includeBuilder,
cancellationToken: cancellationToken,
ignoreSoftDeleteds: ignoreSoftDeleteds
);
//
result = Mapper.Map<XQueryResult<TDto>>(entityResult);
}
catch
{ }
//
return result;
}
#endregion
public virtual void Dispose()
{ }
#endregion
}
}
+38 -27
View File
@@ -1,41 +1,52 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
namespace xDataService.Providers
{
public class XGuidKeyGenerator<TEntity> : IXKeyGenerator<TEntity, Guid>
where TEntity : XBaseEntity<Guid> {
private readonly IXSequentialGuid sequentialGuid;
where TEntity : XBaseEntity<Guid>
{
private readonly IXSequentialGuid sequentialGuid;
public XGuidKeyGenerator (
IXSequentialGuid sequentialGuid = null
) {
this.sequentialGuid = sequentialGuid;
}
public async Task<Guid> GenerateKey (
IXBaseRepository<TEntity, Guid> repository
) {
//
await Task.CompletedTask;
public XGuidKeyGenerator(
IXSequentialGuid sequentialGuid = null
)
{
this.sequentialGuid = sequentialGuid;
}
public async Task<Guid> GenerateKey(
IXBaseRepository<TEntity, Guid> repository,
CancellationToken cancellationToken = default
)
{
//
return await Task.Run(() =>
{
//
// Check if provided SequentialGuid ...
if (sequentialGuid.IsNull ()) {
return Guid.NewGuid ();
} else {
return sequentialGuid.Next ();
if (sequentialGuid.IsNull())
{
return Guid.NewGuid();
}
}
public bool IsEmpty (Guid id) {
//
var result = id.IsNull () || id.IsDefaultGuid ();
//
return result;
}
else
{
return sequentialGuid.Next();
}
}, cancellationToken: cancellationToken);
}
public bool IsEmpty(Guid id)
{
//
var result = id.IsNull() || id.IsDefaultGuid();
//
return result;
}
}
}
+29 -21
View File
@@ -1,33 +1,41 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
namespace xDataService.Providers
{
public class XIntKeyGenerator<TEntity> : IXKeyGenerator<TEntity, int>
where TEntity : XBaseEntity<int> {
public async Task<int> GenerateKey (IXBaseRepository<TEntity, int> repository) {
//
var items = (await repository.GetAllAsync ())
.OrderByDescending (nameof (XBaseEntity<int>.Id));
var last = items
.FirstOrDefault ();
where TEntity : XBaseEntity<int>
{
public async Task<int> GenerateKey(
IXBaseRepository<TEntity, int> repository,
CancellationToken cancellationToken = default
)
{
//
var items = (await repository.GetAllAsync())
.OrderByDescending(nameof(XBaseEntity<int>.Id));
var last = items
.FirstOrDefault();
//
var result = last.IsNull () ? 1 : last.Id + 1;
//
var result = last.IsNull() ? 1 : last.Id + 1;
//
return result;
}
public bool IsEmpty (int id) {
//
var result = id <= 0;
//
return result;
}
//
return result;
}
public bool IsEmpty(int id)
{
//
var result = id <= 0;
//
return result;
}
}
}
+23 -13
View File
@@ -1,15 +1,20 @@
using System;
using xDataService.Interfaces;
namespace xDataService.Helpers {
namespace xDataService.Helpers
{
/// <summary>
/// this service provide Sequential GUID mechanism for Entity Ids ...
/// </summary>
public class XSequentialGuid : IXSequentialGuid {
public class XSequentialGuid : IXSequentialGuid
{
private static int[] sqlOrderMap = null;
private static int[] SQLORDERMAP {
get {
if (sqlOrderMap == null) {
private static int[] SQLORDERMAP
{
get
{
if (sqlOrderMap == null)
{
sqlOrderMap = new int[16] {
3,
2,
@@ -37,24 +42,29 @@ namespace xDataService.Helpers {
private Guid currentGuid;
public XSequentialGuid () {
currentGuid = Guid.NewGuid ();
public XSequentialGuid()
{
currentGuid = Guid.NewGuid();
}
public Guid GetCurrentGuid () {
public Guid GetCurrentGuid()
{
return currentGuid;
}
public Guid Next () {
byte[] bytes = currentGuid.ToByteArray ();
for (int mapIndex = 0; mapIndex < 16; mapIndex++) {
public Guid Next()
{
byte[] bytes = currentGuid.ToByteArray();
for (int mapIndex = 0; mapIndex < 16; mapIndex++)
{
int bytesIndex = SQLORDERMAP[mapIndex];
bytes[bytesIndex]++;
if (bytes[bytesIndex] != 0) {
if (bytes[bytesIndex] != 0)
{
break; // No need to increment more significant bytes
}
}
currentGuid = new Guid (bytes);
currentGuid = new Guid(bytes);
return currentGuid;
}
}
+22 -10
View File
@@ -1,31 +1,43 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
public class XStringKeyGenerator : IXKeyGenerator<XBaseEntity<string>, string> {
namespace xDataService.Providers
{
public class XStringKeyGenerator : IXKeyGenerator<XBaseEntity<string>, string>
{
private readonly IXSequentialGuid sequentialGuid;
public XStringKeyGenerator (IXSequentialGuid sequentialGuid = null) {
public XStringKeyGenerator(IXSequentialGuid sequentialGuid = null)
{
this.sequentialGuid = sequentialGuid;
}
public async Task<string> GenerateKey (IXBaseRepository<XBaseEntity<string>, string> repository) {
public async Task<string> GenerateKey(
IXBaseRepository<XBaseEntity<string>, string> repository,
CancellationToken cancellationToken = default
)
{
//
await Task.CompletedTask;
//
if (sequentialGuid.IsNull ()) {
return Guid.NewGuid ().ToString ();
} else {
return sequentialGuid.Next ().ToString ();
if (sequentialGuid.IsNull())
{
return Guid.NewGuid().ToString();
}
else
{
return sequentialGuid.Next().ToString();
}
}
public bool IsEmpty (string id) {
return id.IsNullOrEmpty ();
public bool IsEmpty(string id)
{
return id.IsNullOrEmpty();
}
}
}