diff --git a/EFRepositories/XBaseEFRepository.cs b/EFRepositories/XBaseEFRepository.cs index 43f438e..5326fd1 100644 --- a/EFRepositories/XBaseEFRepository.cs +++ b/EFRepositories/XBaseEFRepository.cs @@ -11,10 +11,12 @@ using xDataService.Db; using xDataService.Extensions; using xDataService.Interfaces; using xDataService.Models; +using xExceptions.Constants; using xModels.Base; using xModels.Dtos; -namespace xDataService.EFRepositories { +namespace xDataService.EFRepositories +{ /// /// Base EFCore Base Entity Repository Pattern implementation ... /// Only Used on EFCore ... @@ -24,1070 +26,1162 @@ namespace xDataService.EFRepositories { /// is the DbContext Type public abstract class XBaseEFRepository : IXBaseRepository where T : XBaseEntity - where TDbContext : XDbContext { + where TDbContext : XDbContext + { + // + public readonly DbSet dbSet; + private readonly IXKeyGenerator keyGenerator; + public readonly IXUnitOfWorks unitOfWorks; + public readonly XDataServiceConfiguration configuration; + private readonly IXBaseRepositoryEvents baseRepositoryEvents; + + // + public abstract IQueryable GetFullDbSet(); + + // + #region Constructor ... + public XBaseEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXKeyGenerator keyGenerator = null, + IXBaseRepositoryEvents baseRepositoryEvents = null + ) + { + this.keyGenerator = keyGenerator; // - public readonly DbSet dbSet; - private readonly IXKeyGenerator keyGenerator; - public readonly IXUnitOfWorks unitOfWorks; - public readonly XDataServiceConfiguration configuration; - private readonly IXBaseRepositoryEvents baseRepositoryEvents; + this.unitOfWorks = unitOfWorks; + this.configuration = configuration; + this.dbSet = unitOfWorks.GetDbSet(); + this.baseRepositoryEvents = baseRepositoryEvents; + } + #endregion + + // + #region Add ... + public async Task AddAsync( + T item, + bool saveChanges = true + ) + { + // + // Handle Key ... + item = await HandleKeyAsync(item); // - public abstract IQueryable GetFullDbSet (); + var entry = await dbSet.AddAsync(item); // - #region Constructor ... - public XBaseEFRepository ( - IXUnitOfWorks unitOfWorks, - XDataServiceConfiguration configuration, - IXKeyGenerator keyGenerator = null, - IXBaseRepositoryEvents baseRepositoryEvents = null - ) { - this.keyGenerator = keyGenerator; + // Check action is Succeeded or not ... + var isSucceed = false; + if (saveChanges) + { // - this.unitOfWorks = unitOfWorks; - this.configuration = configuration; - this.dbSet = unitOfWorks.GetDbSet (); - this.baseRepositoryEvents = baseRepositoryEvents; - } - #endregion - - // - #region Add ... - public async Task AddAsync ( - T item, - bool saveChanges = true - ) { - // - // Handle Key ... - item = await HandleKeyAsync (item); + // Get Modified Count ... + var qResult = await SaveChangesAsync(); // - 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 (entry.Entity)); - } - - // - // Return result base on action Succeed ... - return isSucceed ? - entry.Entity : - null; + // set isSucceed Value based on Changes ... + isSucceed = qResult > 0; } - public async Task 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 - ); - } + // + // Notify Event ... + if ( + isSucceed && + !baseRepositoryEvents.IsNull() + ) + { + baseRepositoryEvents + .AddEvent(new XBaseEventModel(entry.Entity)); } - public async Task AddRangeAsync ( - IEnumerable items, - bool saveChanges = true - ) { - // - await dbSet.AddRangeAsync ( - await Task - .WhenAll ( - items - .Select (async i => await HandleKeyAsync (i)) - ) + // + // Return result base on action Succeed ... + return isSucceed ? + entry.Entity : + null; + } + + public async Task AddOrUpdateAsync( + T item, + bool saveChanges = true + ) + { + // + var isExists = await IsExistsAsync(GetKey(item)); + if (!isExists) + { + return await AddAsync( + item, + saveChanges ); - - // - // 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> (null)); - } } - #endregion + else + { + return await UpdateAsync( + GetKey(item), + item, + saveChanges + ); + } + } + + public async Task AddRangeAsync( + IEnumerable items, + bool saveChanges = true + ) + { + // + await dbSet.AddRangeAsync( + await Task + .WhenAll( + items + .Select(async i => await HandleKeyAsync(i)) + ) + ); // - #region Remove ... - public async Task RemoveAsync ( - TKey id, - bool softDelete = true, - bool saveChanges = true - ) { + // Check action is Succeeded or not ... + var isSucceed = false; + if (saveChanges) + { // - // Retrieve Item ... - var item = await GetAsync ( - id, - ignoreSoftDeleteds : false - ); - if (item.IsNull ()) { - return null; - } + // Get Modified Count ... + var qResult = await SaveChangesAsync(); // - // Handle Remove ... - EntityEntry entry = null; - if (softDelete && configuration.EnableSoftDelete) { - // + // set isSucceed Value based on Changes ... + isSucceed = qResult > 0; + } + + // + // Notify Event ... + if ( + isSucceed && + !baseRepositoryEvents.IsNull() + ) + { + baseRepositoryEvents + .AddManyEvent(new XBaseEventModel>(null)); + } + } + #endregion + + // + #region Remove ... + public async Task 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 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(entry.Entity)); + } + + // + // Return result base on action Succeed ... + return isSucceed ? + entry.Entity : + null; + } + + public async Task 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 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(entry.Entity)); + } + + // + // Return result base on action Succeed ... + return isSucceed ? + entry.Entity : + null; + } + + public async Task RemoveRangeAsync( + IEnumerable items, + bool softDelete = true, + bool saveChanges = true + ) + { + // + // Handle Remove ... + if (softDelete && configuration.EnableSoftDelete) + { + // + foreach (var item in items) + { 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 (entry.Entity)); - } - - // - // Return result base on action Succeed ... - return isSucceed ? - entry.Entity : - null; + dbSet.UpdateRange(items); } - - public async Task 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 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 (entry.Entity)); - } - - // - // Return result base on action Succeed ... - return isSucceed ? - entry.Entity : - null; + else + { + dbSet.RemoveRange(items); } - public async Task RemoveRangeAsync ( - IEnumerable 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> (null)); - } - } - #endregion - // - #region Retrieve ... - public IQueryable AsQueryable () { - return dbSet.AsQueryable (); + // 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; } - public async Task GetAsync ( - TKey id, - bool ignoreSoftDeleteds = true, - bool containsDetail = false - ) { + // + // Notify Event ... + if ( + isSucceed && + !baseRepositoryEvents.IsNull() + ) + { + baseRepositoryEvents + .RemoveManyEvent(new XBaseEventModel>(null)); + } + } + #endregion + + // + #region Retrieve ... + public IQueryable AsQueryable() + { + return dbSet.AsQueryable(); + } + + public async Task 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> GetAllAsync( + bool ignoreSoftDeleteds = true, + bool containsDetail = false + ) + { + return await Task.Run(() => + { // - var result = await FindOneAsync (i => - GetKey (i) - .ToString () == - id - .ToString (), - ignoreSoftDeleteds : ignoreSoftDeleteds, - containsDetail : containsDetail + var result = GetDbSet( + containsDetail: containsDetail ); - // - return result; - } - - public async Task> 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 FindOneAsync ( - Expression> whereClause, - bool ignoreSoftDeleteds = true, - bool containsDetail = false - ) { - // - // Generate Where Function ... - var whereFunc = whereClause.Compile (); - // // Handle Soft Deleted Items ... - Func ignoreSoftDeletedsWhereFunc = null; - if (ignoreSoftDeleteds && configuration.EnableSoftDelete) { - // - Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; - ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile (); + if (ignoreSoftDeleteds && configuration.EnableSoftDelete) + { + result = result.Where(x => x.Deleted == false); } // - // Get Enumerable ... - var enumerator = GetDbSet ( - containsDetail: containsDetail - ) - .AsAsyncEnumerable (); + return result.AsEnumerable(); + }); + } - // - T result = null; - await - foreach (var entity in enumerator) { - // - var isApproved = whereFunc (entity) && - (ignoreSoftDeletedsWhereFunc.IsNull () ? - true : - ignoreSoftDeletedsWhereFunc (entity)); - if (isApproved) { - // - result = entity; - break; - } - } + public async Task FindOneAsync( + Expression> whereClause, + bool ignoreSoftDeleteds = true, + bool containsDetail = false + ) + { + // + // Generate Where Function ... + var whereFunc = whereClause.Compile(); + // + // Handle Soft Deleted Items ... + Func ignoreSoftDeletedsWhereFunc = null; + if (ignoreSoftDeleteds && configuration.EnableSoftDelete) + { // - return result; + Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; + ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile(); } - public async Task> FindManyAsync ( - Expression> whereClause, - bool ignoreSoftDeleteds = true, - bool containsDetail = false - ) { - // - // Generate Where Function ... - var whereFunc = whereClause.Compile (); + // + // Get Enumerable ... + var enumerator = GetDbSet( + containsDetail: containsDetail + ) + .AsAsyncEnumerable(); + // + T result = null; + await + foreach (var entity in enumerator) + { // - // Handle Soft Deleted Items ... - Func ignoreSoftDeletedsWhereFunc = null; - if (ignoreSoftDeleteds && configuration.EnableSoftDelete) { - // - Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; - ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile (); - } - - // - // Get Enumerable ... - var enumerator = GetDbSet ( - containsDetail: containsDetail - ) - .AsAsyncEnumerable (); - - // - var result = new List (); - 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> 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 ignoreSoftDeletedsWhereFunc = null; - if (ignoreSoftDeleteds && configuration.EnableSoftDelete) { - // - Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; - ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile (); - } - - // - // Get Enumerable ... - var enumerator = GetDbSet ( - containsDetail: query.ContainsDetail - ) - .AsAsyncEnumerable (); - - // - var resultItems = new List (); - await - foreach (var entity in enumerator) { - // - var isApproved = (ignoreSoftDeletedsWhereFunc.IsNull () ? + var isApproved = whereFunc(entity) && + (ignoreSoftDeletedsWhereFunc.IsNull() ? true : - ignoreSoftDeletedsWhereFunc (entity)); - if (isApproved) { - resultItems.Add (entity); - } + ignoreSoftDeletedsWhereFunc(entity)); + if (isApproved) + { + // + result = entity; + break; } + } - // - var result = resultItems.AsEnumerable (); + // + return result; + } - // - // Count Total Items ... - var totalItemsCount = result.Count (); + public async Task> FindManyAsync( + Expression> whereClause, + bool ignoreSoftDeleteds = true, + bool containsDetail = false + ) + { + // + // Generate Where Function ... + var whereFunc = whereClause.Compile(); + // + // Handle Soft Deleted Items ... + Func ignoreSoftDeletedsWhereFunc = null; + if (ignoreSoftDeleteds && configuration.EnableSoftDelete) + { // - // Apply Filter ... - if (!query.Filter.IsNullOrEmpty ()) { - result = await result - .ApplyFilterAsync (query.Filter); + Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; + ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile(); + } + + // + // Get Enumerable ... + var enumerator = GetDbSet( + containsDetail: containsDetail + ) + .AsAsyncEnumerable(); + + // + var result = new List(); + 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> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true + ) + { + // + // Validate ... + if (query.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(configuration); + + // + // Handle Soft Deleted Items ... + Func ignoreSoftDeletedsWhereFunc = null; + if (ignoreSoftDeleteds && configuration.EnableSoftDelete) + { // - // Count Total Items ... - int totalFilteredItemsCount = result.Count (); + Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; + ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile(); + } + // + // Get Enumerable ... + var enumerator = GetDbSet( + containsDetail: query.ContainsDetail + ) + .AsAsyncEnumerable(); + + // + var totalEntities = new List(); + await + foreach (var entity in enumerator) + { // - // Apply Paging ... - result = result - .ApplyPaging ( - query.Page, - query.PageSize); + var isApproved = (ignoreSoftDeletedsWhereFunc.IsNull() ? + true : + ignoreSoftDeletedsWhereFunc(entity)); + if (isApproved) + { + totalEntities.Add(entity); + } + } + // + var items = totalEntities.AsEnumerable(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter); + } + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { // // Apply Sorting ... - if (!query.SortBy.IsNullOrEmpty ()) { - result = result - .ApplySorting ( - query.SortBy, - query.IsAscending); - } - - // - // Generate Result Object ... - // Query = query, - var queryResult = new XQueryResult { - Items = result.AsEnumerable (), - Page = query.Page, - PageSize = query.PageSize, - TotalItems = totalItemsCount, - TotalPages = await PagesCountAsync ( - query.PageSize, - totalFilteredItemsCount - ), - TotalFilteredItems = totalFilteredItemsCount - }; - - // - return queryResult; - } - - public async Task> ConditionalQueryAsync ( - Expression> 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 ignoreSoftDeletedsWhereFunc = null; - if (ignoreSoftDeleteds && configuration.EnableSoftDelete) { - // - Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; - ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile (); - } - - // - // Get Enumerable ... - var enumerator = GetDbSet ( - containsDetail: query.ContainsDetail - ) - .AsAsyncEnumerable (); - - // - var resultItems = new List (); - 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 (query.Filter); - } - - // - // Count Total Items ... - var totalFilteredItemsCount = result.Count (); + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ); // // Apply Paging ... - if (totalItemsCount > 0 && - totalFilteredItemsCount > 0) { - result = result - .ApplyPaging ( - query.Page, - query.PageSize); - - // - // Apply Sorting ... - if (!query.SortBy.IsNullOrEmpty ()) { - result = result - .ApplySorting ( - query.SortBy, - query.IsAscending); - } - } - - // - // Generate Result Object ... - var queryResult = new XQueryResult { - Items = result.AsEnumerable (), - Page = query.Page, - PageSize = query.PageSize, - TotalItems = totalItemsCount, - TotalPages = await PagesCountAsync ( - query.PageSize, - totalFilteredItemsCount - ), - TotalFilteredItems = totalFilteredItemsCount - }; - - // - return queryResult; + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ); } // - // TODO: Fix this ... - // public Task> 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 (request.After); - // result = result.Where (x => GetKey (x).ToString() > lastId.ToString()); - // } - - // // - // result = result.Take (request.First.Value); - // } - - // // - // // Apply Sorting ... - // List nodes = null; - // if (!request.SortBy.IsNullOrEmpty ()) { - // nodes = result - // .ApplySorting ( - // 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 { - // Nodes = nodes, - // TotalCount = totalCount, - // HasNextPage = hasNextPage, - // HasPreviousPage = hasPreviousPage - // }); - // } + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; // - // TODO: Fix this ... - // public Task> RequestConditionalPageAsync ( - // Expression> 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 nodes = null; - // if (!request.SortBy.IsNullOrEmpty ()) { - // nodes = result - // .ApplySorting ( - // 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 { - // Nodes = nodes, - // TotalCount = totalCount, - // HasNextPage = hasNextPage, - // HasPreviousPage = hasPreviousPage - // }); - // } - #endregion - - // - #region Update ... - public async Task 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 (entry.Entity)); - } - - // - // Return result base on action Succeed ... - return isSucceed ? - entry.Entity : - null; - } - - public async Task UpdateRangeAsync ( - IEnumerable 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> (null)); - } - - // - // Return result base on action Succeed ... - return isSucceed; - } - #endregion - - // - #region Count ... - public async Task 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 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 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 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 (); - } - - public async Task 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 items) { - // - if (items.IsNull () || !items.HasChild ()) { - return; - } - - // - items - .ToList () - .ForEach (item => { - Detach (item); - }); - } - - public void Detach (XQueryResult query) { - // - if (query.IsNull () || query.Items.HasChild ()) { - return; - } - - // - Detach (query.Items); - } - - public void Detach (XPageResponse 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 Entry (T item) { - return unitOfWorks.DbContext.Entry (item); - } - - public IQueryable GetDbSet ( - bool containsDetail = false - ) { - // - IQueryable result = null; - if (!containsDetail) { - result = dbSet; - } else { - result = GetFullDbSet (); - } - - // - return result; - } - #endregion + return result; } + + public async Task> ConditionalQueryAsync( + Expression> condition, + XQuery query, + bool ignoreSoftDeleteds = true + ) + { + // + // Validate ... + if (query.IsNull() || condition.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(configuration); + + // + // Handle Soft Deleted Items ... + Func ignoreSoftDeletedsWhereFunc = null; + if (ignoreSoftDeleteds && configuration.EnableSoftDelete) + { + // + Expression> ignoreSoftDeletedsWhereClause = x => x.Deleted == false; + ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile(); + } + + // + // Compile Condition ... + Func conditionFunc = condition.Compile(); + + // + // Get Enumerable ... + var enumerator = GetDbSet( + containsDetail: query.ContainsDetail + ) + .AsAsyncEnumerable(); + + // + var totalEntities = new List(); + await + foreach (var entity in enumerator) + { + // + var isApproved = (ignoreSoftDeletedsWhereFunc.IsNull() ? + true : + ignoreSoftDeletedsWhereFunc(entity)) && + conditionFunc(entity); + if (isApproved) + { + totalEntities.Add(entity); + } + } + + // + var items = totalEntities.AsEnumerable(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter); + } + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Sorting ... + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ); + + // + // Apply Paging ... + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ); + } + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + // + // TODO: Fix this ... + // public Task> 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 (request.After); + // result = result.Where (x => GetKey (x).ToString() > lastId.ToString()); + // } + + // // + // result = result.Take (request.First.Value); + // } + + // // + // // Apply Sorting ... + // List nodes = null; + // if (!request.SortBy.IsNullOrEmpty ()) { + // nodes = result + // .ApplySorting ( + // 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 { + // Nodes = nodes, + // TotalCount = totalCount, + // HasNextPage = hasNextPage, + // HasPreviousPage = hasPreviousPage + // }); + // } + + // + // TODO: Fix this ... + // public Task> RequestConditionalPageAsync ( + // Expression> 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 nodes = null; + // if (!request.SortBy.IsNullOrEmpty ()) { + // nodes = result + // .ApplySorting ( + // 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 { + // Nodes = nodes, + // TotalCount = totalCount, + // HasNextPage = hasNextPage, + // HasPreviousPage = hasPreviousPage + // }); + // } + #endregion + + // + #region Update ... + public async Task 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(entry.Entity)); + } + + // + // Return result base on action Succeed ... + return isSucceed ? + entry.Entity : + null; + } + + public async Task UpdateRangeAsync( + IEnumerable 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>(null)); + } + + // + // Return result base on action Succeed ... + return isSucceed; + } + #endregion + + // + #region Count ... + public async Task 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 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 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 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(); + } + + public async Task 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 items) + { + // + if (items.IsNull() || !items.HasChild()) + { + return; + } + + // + items + .ToList() + .ForEach(item => + { + Detach(item); + }); + } + + public void Detach(XQueryResult query) + { + // + if (query.IsNull() || query.Items.HasChild()) + { + return; + } + + // + Detach(query.Items); + } + + public void Detach(XPageResponse 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 Entry(T item) + { + return unitOfWorks.DbContext.Entry(item); + } + + public IQueryable GetDbSet( + bool containsDetail = false + ) + { + // + IQueryable result = null; + if (!containsDetail) + { + result = dbSet; + } + else + { + result = GetFullDbSet(); + } + + // + return result; + } + #endregion + } } \ No newline at end of file