1093 lines
36 KiB
C#
1093 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using xCommons.Extensions;
|
|
using xDataService.Configuration;
|
|
using xDataService.Db;
|
|
using xDataService.Extensions;
|
|
using xDataService.Interfaces;
|
|
using xDataService.Models;
|
|
using xModels.Base;
|
|
using xModels.Dtos;
|
|
|
|
namespace xDataService.EFRepositories {
|
|
/// <summary>
|
|
/// Base EFCore Base Entity Repository Pattern implementation ...
|
|
/// Only Used on EFCore ...
|
|
/// </summary>
|
|
/// <typeparam name="T">is the Entity type</typeparam>
|
|
/// <typeparam name="TKey">is the Entity Key Type</typeparam>
|
|
/// <typeparam name="TDbContext">is the DbContext Type</typeparam>
|
|
public abstract class XBaseEFRepository<T, TKey, TDbContext> : IXBaseRepository<T, TKey>
|
|
where T : XBaseEntity<TKey>
|
|
where TDbContext : XDbContext {
|
|
//
|
|
public readonly DbSet<T> dbSet;
|
|
private readonly IXKeyGenerator<T, TKey> keyGenerator;
|
|
public readonly IXUnitOfWorks<TDbContext> unitOfWorks;
|
|
public readonly XDataServiceConfiguration configuration;
|
|
private readonly IXBaseRepositoryEvents<T> baseRepositoryEvents;
|
|
|
|
//
|
|
public abstract IQueryable<T> GetFullDbSet ();
|
|
|
|
//
|
|
#region Constructor ...
|
|
public XBaseEFRepository (
|
|
IXUnitOfWorks<TDbContext> unitOfWorks,
|
|
XDataServiceConfiguration configuration,
|
|
IXKeyGenerator<T, TKey> keyGenerator = null,
|
|
IXBaseRepositoryEvents<T> baseRepositoryEvents = null
|
|
) {
|
|
this.keyGenerator = keyGenerator;
|
|
//
|
|
this.unitOfWorks = unitOfWorks;
|
|
this.configuration = configuration;
|
|
this.dbSet = unitOfWorks.GetDbSet<T, TKey> ();
|
|
this.baseRepositoryEvents = baseRepositoryEvents;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Add ...
|
|
public async Task<T> AddAsync (
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Handle Key ...
|
|
item = await HandleKeyAsync (item);
|
|
|
|
//
|
|
var entry = await dbSet.AddAsync (item);
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.AddEvent (new XBaseEventModel<T> (entry.Entity));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
entry.Entity :
|
|
null;
|
|
}
|
|
|
|
public async Task<T> AddOrUpdateAsync (
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
var isExists = await IsExistsAsync (GetKey (item));
|
|
if (!isExists) {
|
|
return await AddAsync (
|
|
item,
|
|
saveChanges
|
|
);
|
|
} else {
|
|
return await UpdateAsync (
|
|
GetKey (item),
|
|
item,
|
|
saveChanges
|
|
);
|
|
}
|
|
}
|
|
|
|
public async Task AddRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
await dbSet.AddRangeAsync (
|
|
await Task
|
|
.WhenAll (
|
|
items
|
|
.Select (async i => await HandleKeyAsync (i))
|
|
)
|
|
);
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.AddManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Remove ...
|
|
public async Task<T> RemoveAsync (
|
|
TKey id,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Retrieve Item ...
|
|
var item = await GetAsync (
|
|
id,
|
|
ignoreSoftDeleteds : false
|
|
);
|
|
if (item.IsNull ()) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Handle Remove ...
|
|
EntityEntry<T> entry = null;
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
item.Deleted = true;
|
|
entry = dbSet.Update (item);
|
|
} else {
|
|
entry = dbSet.Remove (item);
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.RemoveEvent (new XBaseEventModel<T> (entry.Entity));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
entry.Entity :
|
|
null;
|
|
}
|
|
|
|
public async Task<T> RemoveAsync (
|
|
T item,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Check item Exists ...
|
|
var isExists = await IsExistsAsync (
|
|
GetKey (item),
|
|
ignoreSoftDeleteds : false
|
|
);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Handle Remove ...
|
|
EntityEntry<T> entry = null;
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
item.Deleted = true;
|
|
entry = dbSet.Update (item);
|
|
} else {
|
|
entry = dbSet.Remove (item);
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.RemoveEvent (new XBaseEventModel<T> (entry.Entity));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
entry.Entity :
|
|
null;
|
|
}
|
|
|
|
public async Task RemoveRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Handle Remove ...
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
foreach (var item in items) {
|
|
item.Deleted = true;
|
|
}
|
|
|
|
//
|
|
dbSet.UpdateRange (items);
|
|
} else {
|
|
dbSet.RemoveRange (items);
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.RemoveManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Retrieve ...
|
|
public IQueryable<T> AsQueryable () {
|
|
return dbSet.AsQueryable ();
|
|
}
|
|
|
|
public async Task<T> GetAsync (
|
|
TKey id,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
var result = await FindOneAsync (i =>
|
|
GetKey (i)
|
|
.ToString () ==
|
|
id
|
|
.ToString (),
|
|
ignoreSoftDeleteds : ignoreSoftDeleteds,
|
|
containsDetail : containsDetail
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
public async Task<IEnumerable<T>> GetAllAsync (
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
return await Task.Run (() => {
|
|
//
|
|
var result = GetDbSet (
|
|
containsDetail: containsDetail
|
|
);
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
result = result.Where (x => x.Deleted == false);
|
|
}
|
|
|
|
//
|
|
return result.AsEnumerable ();
|
|
});
|
|
}
|
|
|
|
public async Task<T> FindOneAsync (
|
|
Expression<Func<T, bool>> whereClause,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
// Generate Where Function ...
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = GetDbSet (
|
|
containsDetail: containsDetail
|
|
)
|
|
.AsAsyncEnumerable ();
|
|
|
|
//
|
|
T result = null;
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
//
|
|
result = entity;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
public async Task<IEnumerable<T>> FindManyAsync (
|
|
Expression<Func<T, bool>> whereClause,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
// Generate Where Function ...
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = GetDbSet (
|
|
containsDetail: containsDetail
|
|
)
|
|
.AsAsyncEnumerable ();
|
|
|
|
//
|
|
var result = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
result.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result.AsEnumerable ();
|
|
}
|
|
|
|
public async Task<XQueryResult<T>> QueryAsync (
|
|
XQuery query,
|
|
bool ignoreSoftDeleteds = true
|
|
) {
|
|
//
|
|
if (query.PageSize < configuration
|
|
.PagingConfiguration
|
|
.MinAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.DefaultPageSize;
|
|
}
|
|
|
|
//
|
|
if (query.PageSize > configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize;
|
|
}
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = GetDbSet (
|
|
containsDetail: query.ContainsDetail
|
|
)
|
|
.AsAsyncEnumerable ();
|
|
|
|
//
|
|
var resultItems = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = (ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
resultItems.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
var result = resultItems.AsEnumerable ();
|
|
|
|
//
|
|
// Count Total Items ...
|
|
var totalItemsCount = result.Count ();
|
|
|
|
//
|
|
// Apply Filter ...
|
|
if (!query.Filter.IsNullOrEmpty ()) {
|
|
result = await result
|
|
.ApplyFilterAsync<T, TKey> (query.Filter);
|
|
}
|
|
|
|
//
|
|
// Count Total Items ...
|
|
int totalFilteredItemsCount = result.Count ();
|
|
|
|
//
|
|
// Apply Paging ...
|
|
result = result
|
|
.ApplyPaging (
|
|
query.Page,
|
|
query.PageSize);
|
|
|
|
//
|
|
// Apply Sorting ...
|
|
if (!query.SortBy.IsNullOrEmpty ()) {
|
|
result = result
|
|
.ApplySorting<T, TKey> (
|
|
query.SortBy,
|
|
query.IsAscending);
|
|
}
|
|
|
|
//
|
|
// Generate Result Object ...
|
|
// Query = query,
|
|
var queryResult = new XQueryResult<T> {
|
|
Items = result.AsEnumerable (),
|
|
Page = query.Page,
|
|
PageSize = query.PageSize,
|
|
TotalItems = totalItemsCount,
|
|
TotalPages = await PagesCountAsync (
|
|
query.PageSize,
|
|
totalFilteredItemsCount
|
|
),
|
|
TotalFilteredItems = totalFilteredItemsCount
|
|
};
|
|
|
|
//
|
|
return queryResult;
|
|
}
|
|
|
|
public async Task<XQueryResult<T>> ConditionalQueryAsync (
|
|
Expression<Func<T, bool>> condition,
|
|
XQuery query,
|
|
bool ignoreSoftDeleteds = true
|
|
) {
|
|
//
|
|
if (query.PageSize < configuration
|
|
.PagingConfiguration
|
|
.MinAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.DefaultPageSize;
|
|
}
|
|
|
|
//
|
|
if (query.PageSize > configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize;
|
|
}
|
|
|
|
//
|
|
// Generate Where Function ...
|
|
var whereFunc = condition.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = GetDbSet (
|
|
containsDetail: query.ContainsDetail
|
|
)
|
|
.AsAsyncEnumerable ();
|
|
|
|
//
|
|
var resultItems = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
resultItems.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
var result = resultItems.AsQueryable ();
|
|
|
|
//
|
|
// Count Total Items ...
|
|
var totalItemsCount = result.Count ();
|
|
|
|
//
|
|
// Apply Filter ...
|
|
if (totalItemsCount > 0 &&
|
|
!query.Filter.IsNullOrEmpty ()) {
|
|
result = result
|
|
.ApplyFilter<T, TKey> (query.Filter);
|
|
}
|
|
|
|
//
|
|
// Count Total Items ...
|
|
var totalFilteredItemsCount = result.Count ();
|
|
|
|
//
|
|
// Apply Paging ...
|
|
if (totalItemsCount > 0 &&
|
|
totalFilteredItemsCount > 0) {
|
|
result = result
|
|
.ApplyPaging (
|
|
query.Page,
|
|
query.PageSize);
|
|
|
|
//
|
|
// Apply Sorting ...
|
|
if (!query.SortBy.IsNullOrEmpty ()) {
|
|
result = result
|
|
.ApplySorting<T, TKey> (
|
|
query.SortBy,
|
|
query.IsAscending);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Generate Result Object ...
|
|
var queryResult = new XQueryResult<T> {
|
|
Items = result.AsEnumerable (),
|
|
Page = query.Page,
|
|
PageSize = query.PageSize,
|
|
TotalItems = totalItemsCount,
|
|
TotalPages = await PagesCountAsync (
|
|
query.PageSize,
|
|
totalFilteredItemsCount
|
|
),
|
|
TotalFilteredItems = totalFilteredItemsCount
|
|
};
|
|
|
|
//
|
|
return queryResult;
|
|
}
|
|
|
|
//
|
|
// TODO: Fix this ...
|
|
// public Task<XPageResponse<T>> RequestPageAsync (
|
|
// XPageRequest request,
|
|
// bool ignoreSoftDeleteds = true,
|
|
// bool containsDetail = true
|
|
// ) {
|
|
// //
|
|
// var result = GetDbSet (
|
|
// containsDetail: containsDetail
|
|
// );
|
|
|
|
// //
|
|
// // Handle Soft Deleted Items ...
|
|
// if (ignoreSoftDeleteds) {
|
|
// result = result.Where (x => x.Deleted == false);
|
|
// }
|
|
|
|
// //
|
|
// if (request.First.HasValue) {
|
|
// //
|
|
// if (!request.After.IsNullOrEmpty ()) {
|
|
// //
|
|
// TKey lastId = XCursorHelper.FromCursor<TKey> (request.After);
|
|
// result = result.Where (x => GetKey (x).ToString() > lastId.ToString());
|
|
// }
|
|
|
|
// //
|
|
// result = result.Take (request.First.Value);
|
|
// }
|
|
|
|
// //
|
|
// // Apply Sorting ...
|
|
// List<T> nodes = null;
|
|
// if (!request.SortBy.IsNullOrEmpty ()) {
|
|
// nodes = result
|
|
// .ApplySorting<T, TKey> (
|
|
// request.SortBy, !request.DescendingSort
|
|
// ).ToList ();
|
|
// }
|
|
|
|
// //
|
|
// // Claculate Required Info ...
|
|
// int totalCount = result.CountAsync ().Result;
|
|
// int maxId = nodes.Max (x => Convert.ToInt32 (GetKey (x)));
|
|
// int minId = nodes.Min (x => Convert.ToInt32 (GetKey (x)));
|
|
// bool hasNextPage = nodes.Any (x => Convert.ToInt32 (GetKey (x)) > maxId);
|
|
// bool hasPreviousPage = nodes.Any (x => Convert.ToInt32 (GetKey (x)) < minId);
|
|
|
|
// //
|
|
// return Task.FromResult (new XPageResponse<T> {
|
|
// Nodes = nodes,
|
|
// TotalCount = totalCount,
|
|
// HasNextPage = hasNextPage,
|
|
// HasPreviousPage = hasPreviousPage
|
|
// });
|
|
// }
|
|
|
|
//
|
|
// TODO: Fix this ...
|
|
// public Task<XPageResponse<T>> RequestConditionalPageAsync (
|
|
// Expression<Func<T, bool>> condition,
|
|
// XPageRequest request,
|
|
// bool ignoreSoftDeleteds = true,
|
|
// bool containsDetail = true
|
|
// ) {
|
|
// //
|
|
// var result = GetDbSet (
|
|
// containsDetail: containsDetail
|
|
// )
|
|
// .Where (condition);
|
|
|
|
// //
|
|
// // Handle Soft Deleted Items ...
|
|
// if (ignoreSoftDeleteds) {
|
|
// result = result.Where (x => x.Deleted == false);
|
|
// }
|
|
|
|
// //
|
|
// if (request.First.HasValue) {
|
|
// //
|
|
// if (!request.After.IsNullOrEmpty ()) {
|
|
// //
|
|
// int lastId = XCursorHelper.FromCursor (request.After);
|
|
// result = result.Where (x => Convert.ToInt32 (GetKey (x)) > lastId);
|
|
// }
|
|
|
|
// //
|
|
// result = result.Take (request.First.Value);
|
|
// }
|
|
|
|
// //
|
|
// // Apply Sorting ...
|
|
// List<T> nodes = null;
|
|
// if (!request.SortBy.IsNullOrEmpty ()) {
|
|
// nodes = result
|
|
// .ApplySorting<T, TKey> (
|
|
// request.SortBy, !request.DescendingSort)
|
|
// .ToList ();
|
|
// }
|
|
|
|
// //
|
|
// // Claculate Required Info ...
|
|
// int totalCount = result.CountAsync ().Result;
|
|
// int maxId = nodes.Max (x => Convert.ToInt32 (GetKey (x)));
|
|
// int minId = nodes.Min (x => Convert.ToInt32 (GetKey (x)));
|
|
// bool hasNextPage = result.Any (x => Convert.ToInt32 (GetKey (x)) > maxId);
|
|
// bool hasPreviousPage = result.Any (x => Convert.ToInt32 (GetKey (x)) < minId);
|
|
|
|
// //
|
|
// return Task.FromResult (new XPageResponse<T> {
|
|
// Nodes = nodes,
|
|
// TotalCount = totalCount,
|
|
// HasNextPage = hasNextPage,
|
|
// HasPreviousPage = hasPreviousPage
|
|
// });
|
|
// }
|
|
#endregion
|
|
|
|
//
|
|
#region Update ...
|
|
public async Task<T> UpdateAsync (
|
|
TKey id,
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Get Exists Entity ...
|
|
var existsEntity = await GetAsync (
|
|
id,
|
|
containsDetail : true,
|
|
ignoreSoftDeleteds : false
|
|
);
|
|
|
|
//
|
|
// Update Data ...
|
|
existsEntity.UpdateData (item);
|
|
var entry = dbSet.Attach (existsEntity);
|
|
entry.State = EntityState.Modified;
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.UpdateEvent (new XBaseEventModel<T> (entry.Entity));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
entry.Entity :
|
|
null;
|
|
}
|
|
|
|
public async Task<bool> UpdateRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
items
|
|
.ToList ()
|
|
.ForEach (i => {
|
|
var entry = dbSet.Attach (i);
|
|
entry.State = EntityState.Modified;
|
|
});
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.UpdateManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Count ...
|
|
public async Task<int> CountAsync (bool ignoreSoftDeleteds = true) {
|
|
//
|
|
var dbSet = GetDbSet ();
|
|
|
|
//
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
return await dbSet.CountAsync (i => i.Deleted == false);
|
|
} else {
|
|
return await dbSet.CountAsync ();
|
|
}
|
|
}
|
|
|
|
public async Task<int> PagesCountAsync (
|
|
int pageSize,
|
|
int? totalItems = null
|
|
) {
|
|
//
|
|
int count = totalItems.HasValue ? totalItems.Value : await CountAsync ();
|
|
int pagesCount = count / pageSize;
|
|
|
|
//
|
|
if (count % pageSize > 0) {
|
|
pagesCount++;
|
|
}
|
|
|
|
//
|
|
return pagesCount;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Exists ...
|
|
public async Task<bool> IsExistsAsync (
|
|
TKey id,
|
|
bool ignoreSoftDeleteds = true
|
|
) {
|
|
//
|
|
var result = await FindOneAsync (i =>
|
|
GetKey (i)
|
|
.ToString () == id
|
|
.ToString (),
|
|
ignoreSoftDeleteds : ignoreSoftDeleteds,
|
|
containsDetail : false
|
|
);
|
|
|
|
//
|
|
Detach (result);
|
|
|
|
//
|
|
return !result.IsNull ();
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Unit Of Work ...
|
|
public async Task<int> SaveChangesAsync () {
|
|
return await unitOfWorks.SaveChangesAsync ();
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Keys ...
|
|
public void SetKey (
|
|
ref T item,
|
|
TKey id
|
|
) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var keyProp = props.FirstOrDefault (p => p.Name == "Id");
|
|
if (keyProp.IsNull ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
Type t = Nullable.GetUnderlyingType (keyProp.PropertyType) ?? keyProp.PropertyType;
|
|
object safeValue = (id == null) ? null : Convert.ChangeType (id, t);
|
|
keyProp.SetValue (item, safeValue, null);
|
|
}
|
|
|
|
public TKey GetKey (T item) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var keyProp = props.FirstOrDefault (p => p.Name == "Id");
|
|
|
|
//
|
|
var keyString = string.Empty;
|
|
if (keyProp.IsNull ()) {
|
|
keyString = string.Empty;
|
|
} else {
|
|
keyString = keyProp.GetValue (item).ToString ();
|
|
}
|
|
|
|
//
|
|
if (keyString.IsNullOrEmpty ()) {
|
|
return default (TKey);
|
|
}
|
|
|
|
//
|
|
// Prevent Deserializing issues throug JsonReader ...
|
|
if (keyString.IsGuid () && typeof (TKey) == typeof (Guid)) {
|
|
return item.Id;
|
|
}
|
|
|
|
//
|
|
return keyString.FromJSON<TKey> ();
|
|
}
|
|
|
|
public async Task<T> HandleKeyAsync (T item) {
|
|
//
|
|
var keyType = typeof (TKey);
|
|
|
|
//
|
|
// Handle Guid Key Type ...
|
|
// Since EFCore has AutoIncrement on int Ids, there is no need to handle int Key types ...
|
|
if (
|
|
(
|
|
keyType == typeof (Guid) ||
|
|
keyType == typeof (string)
|
|
) &&
|
|
keyGenerator.IsEmpty (item.Id)
|
|
) {
|
|
//
|
|
var newKey = await keyGenerator.GenerateKey (this);
|
|
|
|
//
|
|
SetKey (ref item, newKey);
|
|
}
|
|
|
|
//
|
|
return item;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Detach ...
|
|
public void Detach (T item) {
|
|
//
|
|
if (item.IsNull ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
Entry (item).State = EntityState.Detached;
|
|
}
|
|
|
|
public void Detach (IEnumerable<T> items) {
|
|
//
|
|
if (items.IsNull () || !items.HasChild ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
items
|
|
.ToList ()
|
|
.ForEach (item => {
|
|
Detach (item);
|
|
});
|
|
}
|
|
|
|
public void Detach (XQueryResult<T> query) {
|
|
//
|
|
if (query.IsNull () || query.Items.HasChild ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
Detach (query.Items);
|
|
}
|
|
|
|
public void Detach (XPageResponse<T> page) {
|
|
//
|
|
if (page.IsNull () || !page.Nodes.HasChild ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
Detach (page.Nodes);
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Others ...
|
|
public void Dispose () {
|
|
unitOfWorks.Dispose ();
|
|
}
|
|
|
|
public string GetPropValues (T item) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var vals = props.Select (p => p.GetValue (p.Name));
|
|
|
|
//
|
|
return vals.ToJSON ();
|
|
}
|
|
|
|
public EntityEntry<T> Entry (T item) {
|
|
return unitOfWorks.DbContext.Entry (item);
|
|
}
|
|
|
|
public IQueryable<T> GetDbSet (
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
IQueryable<T> result = null;
|
|
if (!containsDetail) {
|
|
result = dbSet;
|
|
} else {
|
|
result = GetFullDbSet ();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
#endregion
|
|
}
|
|
} |