### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Configuration\XDataBaseConfiguration.cs using System.Collections.Generic; using xDataService.Constants; namespace xDataService.Configuration { /// /// Describe a Database ... /// public class XDataBaseConfiguration { /// /// Provider Type ... /// /// public XDbProviders Provider { get; set; } /// /// Connection String which provide Requires Data to Connect to Db Provider ... /// /// public string ConnectionString { get; set; } /// /// Holds Seeding items ... /// nameof(TEntity) => TEntity /// public IDictionary> SeedItems { get; set; } = new Dictionary>(); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Configuration\XDataServiceConfiguration.cs using System.Collections.Generic; using xDataService.Constants; namespace xDataService.Configuration { /// /// Represent Configurations of DataService Module ... /// public partial class XDataServiceConfiguration { /// /// the base path for providing GraphQL ... /// /// public string GraphQLBasePath { get; set; } = "/graphql"; /// /// Data Bases Configuration ... /// /// public IDictionary Databases { get; set; } = new Dictionary(); /// /// Enable Soft Delete Entities or Not ... /// /// public bool EnableSoftDelete { get; set; } /// /// Specified Seeding Mode ... /// public XDbSeedingMode SeedingMode { get; set; } = XDbSeedingMode.None; /// /// Enable Tracking of Entities ... /// Only Used on EFCore ... /// /// public bool EnableTracking { get; set; } = false; /// /// Enable Logging Details of Errors ... /// Only Used on EFCore ... /// /// public bool EnableDetailedErrors { get; set; } = false; /// /// Enable Logging Sensitive Data ... /// Only Used on EFCore ... /// /// public bool EnableSensitiveDataLogging { get; set; } = false; /// /// this is a way to provide Default Pagination Data on XQuery based requests ... /// /// public PagingConfiguration PagingConfiguration { get; set; } = new PagingConfiguration(); } /// /// this is a way to provide Default Pagination Data on XQuery based requests ... /// public partial class PagingConfiguration { /// /// Default Page Size ... /// /// public int DefaultPageSize { get; set; } = XDataServiceConstants.DEFAULT_PAGE_SIZE; /// /// restrict Maximum Page Size ... /// /// public int MaxAvailablePageSize { get; set; } = XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE; /// /// restrice Minimum Page Size ... /// /// public int MinAvailablePageSize { get; set; } = XDataServiceConstants.MIN_AVAILABLE_PAGE_SIZE; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Constants\ConfigurationNodeNames.cs namespace xDataService.Constants { public partial struct ConfigurationNodeNames { public const string DB_PROVIDER_NODE = "XDBProvider"; public const string DATA_SERVICE_NODE = "DataServiceConfiguration"; public const string DATA_SERVICE_DB_SEED_NODE = "DbSeeder"; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Constants\XDataServiceConstants.cs namespace xDataService.Constants { /// /// Default Pagination Values ... /// public partial struct XDataServiceConstants { public static int DEFAULT_PAGE_SIZE = 50; public static int MAX_AVAILABLE_PAGE_SIZE = 500; public static int MIN_AVAILABLE_PAGE_SIZE = 20; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Constants\XDbProviders.cs namespace xDataService.Constants { /// /// Represent Supported DBMS for Managing Data ... /// public enum XDbProviders { None, MySQL, SQLite, Oracle, SQLServer, MongoDB, } /// /// Represent Supported DBMS for Managing Data ... /// public partial struct ProviderType { public const string MySQL = "MYSQL"; public const string SQLite = "SQLITE"; public const string Oracle = "ORACLE"; public const string MongoDB = "MONGODB"; public const string SQLServer = "SQLSERVER"; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Constants\XDbSeedingMode.cs namespace xDataService.Constants { /// /// All Seeding Data Mode ... /// public enum XDbSeedingMode { /// /// No Seed Data ... /// None, /// /// Seed Only New Items ... /// AddIfNotExists, /// /// Seed Force (Add/Update) ... /// AddOrUpdate, } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Constants\XRepositoryType.cs using xExceptions.Attributes; namespace xDataService.Constants { public enum XRepositoryType { [StringValue("EF")] EF, [StringValue("Mongo")] Mongo, [StringValue("InMemory")] InMemory } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Controllers\XBaseRepositoryController.cs using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using xCommons.Configurations; using xCommons.Extensions; using xCommons.Providers; using xExceptions.Constants; using xModels.Base; using xModels.Dtos; using xDataService.Interfaces; using System.Linq; using Microsoft.EntityFrameworkCore.Query; using System.Threading; using xCommons.Controllers; using Microsoft.AspNetCore.Authorization; namespace xDataService.Controllers { /// /// an Abstract Controller for Providing Entity Repository Actions Implementatin ... /// /// /// [AllowAnonymous] public abstract class XBaseRepositoryController : XBaseApiV1Controller, IXBaseRepositoryController where TEntity : XBaseEntity { // #region Properties ... public IXBaseRepository Repository { get; } public Func, IOrderedQueryable> DefaultOrderBuilder { get; } public Func, IIncludableQueryable> DefaultIncludeBuilder { get; } #endregion // #region Constructor ... protected XBaseRepositoryController( ILogger> logger, XAppConfiguration appConfiguration, XValidationProvider validationProvider, IXBaseRepository repository, Func, IOrderedQueryable> defaultOrderBuilder = null, Func, IIncludableQueryable> defaultIncludeBuilder = null ) : base( logger, appConfiguration, validationProvider ) { // Repository = repository; DefaultOrderBuilder = defaultOrderBuilder; DefaultIncludeBuilder = defaultIncludeBuilder; } #endregion // #region Actions ... // #region Add ... /// /// Add Specified Item ... /// /// /// /// /// /// [HttpPost] public virtual async Task> Add( [FromBody] TEntity item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } ValidationProvider.NotNull(item); // // Get Result ... var result = await Repository .AddAsync( item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Add or Update Specified Item ... /// /// /// /// /// /// [HttpPost("AddOrUpdate")] public virtual async Task> AddOrUpdate( [FromBody] TEntity item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } ValidationProvider.NotNull(item); // // Get Result ... var result = await Repository .AddOrUpdateAsync( item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Add a Collection of Items ... /// /// /// /// /// /// [HttpPost("AddMany")] public virtual async Task AddMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... await Repository .AddRangeAsync( request.Items, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Retrieve ... /// /// Get Specified Item ... /// /// /// /// /// /// /// /// [HttpGet("{id}")] public virtual async Task> Get( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await Repository .GetAsync( id, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Get All Items ... /// /// /// /// /// /// /// /// [HttpGet] public virtual async Task>> GetAll( [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Get Result ... var result = await Repository .GetAllAsync( orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Find Specified Item ... /// /// /// /// /// /// /// /// [HttpGet("FindOne/{query}")] public virtual async Task> FindOne( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotEmpty(query); // // Get Result ... var result = await Repository .FindOneAsync( predicate: t => t.PropValuesContains(query), includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Find Many Items ... /// /// /// /// /// /// /// /// /// [HttpGet("FindMany/{query}")] public virtual async Task>> FindMany( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotEmpty(query); // // Get Result ... var result = await Repository .FindManyAsync( predicate: t => t.PropValuesContains(query), orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Retrieve Items Based on Query Mechanism ... /// /// /// /// /// /// /// /// /// [HttpGet("Query")] public virtual async Task>> Query( [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(query); // // Get Result ... var result = await Repository .QueryAsync( query: query, orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Update ... /// /// Update Item ... /// /// /// /// /// /// /// [HttpPut("{id}")] public virtual async Task> Update( [FromRoute] TKey id, [FromBody] TEntity item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(id, item) .ValidateGroupAsync(); // // Get Result ... var result = await Repository .UpdateAsync( id: id, item: item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Update a Collection of items ... /// /// /// /// /// /// [HttpPost("UpdateMany")] public virtual async Task> UpdateMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... var result = await Repository .UpdateRangeAsync( saveChanges: true, items: request.Items, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Exists ... /// ///Check an Item Exists or not ... /// /// /// /// /// /// /// [HttpGet("{id}/IsExists")] public virtual async Task> IsExists( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await Repository .IsExistsAsync( id: id, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Remove ... /// /// Remove an Items ... /// /// /// /// /// /// /// [HttpDelete("{id}")] public virtual async Task> Remove( [FromRoute] TKey id, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await Repository .RemoveAsync( id: id, saveChanges: true, softDelete: softDelete, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Remove Many Items ... /// /// /// /// /// /// /// [HttpPost("RemoveMany")] public virtual async Task RemoveMany( [FromBody] XBaseRangeRequest request, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... await Repository .RemoveRangeAsync( saveChanges: true, items: request.Items, softDelete: softDelete, cancellationToken: cancellationToken ); // return Ok(); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Controllers\XBaseServiceController.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Query; using Microsoft.Extensions.Logging; using xCommons.Configurations; using xCommons.Controllers; using xCommons.Extensions; using xCommons.Providers; using xDataService.Interfaces; using xExceptions.Constants; using xModels.Base; using xModels.Dtos; namespace xDataService.Controllers { /// /// an Abstract Controller for Providing Entity Dto Repository Service Actions Implementatin ... /// /// /// /// [AllowAnonymous] public abstract class XBaseServiceController : XBaseApiV1Controller, IXBaseServiceController where TEntity : XBaseEntity where TDto : XBaseEntityDto { // #region Properties ... public IXBaseRepositoryService RepositoryService { get; } public Func, IOrderedQueryable> DefaultOrderBuilder { get; } public Func, IIncludableQueryable> DefaultIncludeBuilder { get; } #endregion // #region Constructor ... protected XBaseServiceController( ILogger> logger, XAppConfiguration appConfiguration, XValidationProvider validationProvider, IXBaseRepositoryService repositoryService, Func, IOrderedQueryable> defaultOrderBuilder = null, Func, IIncludableQueryable> defaultIncludeBuilder = null ) : base( logger, appConfiguration, validationProvider ) { // RepositoryService = repositoryService; DefaultOrderBuilder = defaultOrderBuilder; DefaultIncludeBuilder = defaultIncludeBuilder; } #endregion // #region Actions ... // #region Add ... /// /// Add Specified Item ... /// /// /// /// /// /// [HttpPost] public virtual async Task> Add( [FromBody] TDto item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } ValidationProvider.NotNull(item); // // Get Result ... var result = await RepositoryService .AddAsync( item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Add or Update Specified Item ... /// /// /// /// /// /// [HttpPost("AddOrUpdate")] public virtual async Task> AddOrUpdate( [FromBody] TDto item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } ValidationProvider.NotNull(item); // // Get Result ... var result = await RepositoryService .AddOrUpdateAsync( item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Add a Collection of Items ... /// /// /// /// /// /// [HttpPost("AddMany")] public virtual async Task AddMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... await RepositoryService .AddRangeAsync( request.Items, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Retrieve ... /// /// Get Specified Item ... /// /// /// /// /// /// /// /// [HttpGet("{id}")] public virtual async Task> Get( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await RepositoryService .GetAsync( id, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Get All Items ... /// /// /// /// /// /// /// /// [HttpGet] public virtual async Task>> GetAll( [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Get Result ... var result = await RepositoryService .GetAllAsync( orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Find Specified Item ... /// /// /// /// /// /// /// /// [HttpGet("FindOne/{query}")] public virtual async Task> FindOne( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotEmpty(query); // // Get Result ... var result = await RepositoryService .FindOneAsync( predicate: t => t.PropValuesContains(query), includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Find Many Items ... /// /// /// /// /// /// /// /// /// [HttpGet("FindMany/{query}")] public virtual async Task>> FindMany( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotEmpty(query); // // Get Result ... var result = await RepositoryService .FindManyAsync( predicate: t => t.PropValuesContains(query), orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Retrieve Items Based on Query Mechanism ... /// /// /// /// /// /// /// /// /// [HttpGet("Query")] public virtual async Task>> Query( [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(query); // // Get Result ... var result = await RepositoryService .QueryAsync( query: query, orderBuilder: useDefaultOrders ? DefaultOrderBuilder : null, includeBuilder: useDefaultIncludes ? DefaultIncludeBuilder : null, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Update ... /// /// Update Item ... /// /// /// /// /// /// /// [HttpPut("{id}")] public virtual async Task> Update( [FromRoute] TKey id, [FromBody] TDto item, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(id, item) .ValidateGroupAsync(); // // Get Result ... var result = await RepositoryService .UpdateAsync( id: id, item: item, saveChanges: true, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Update a Collection of items ... /// /// /// /// /// /// [HttpPost("UpdateMany")] public virtual async Task> UpdateMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... if (!ModelState.IsValid) { XException.InvalidArgs.Throw(); } await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... var result = await RepositoryService .UpdateRangeAsync( saveChanges: true, items: request.Items, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Exists ... /// ///Check an Item Exists or not ... /// /// /// /// /// /// /// [HttpGet("{id}/IsExists")] public virtual async Task> IsExists( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await RepositoryService .IsExistsAsync( id: id, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion // #region Remove ... /// /// Remove an Items ... /// /// /// /// /// /// /// [HttpDelete("{id}")] public virtual async Task> Remove( [FromRoute] TKey id, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... ValidationProvider.NotNull(id); // // Get Result ... var result = await RepositoryService .RemoveAsync( id: id, saveChanges: true, softDelete: softDelete, cancellationToken: cancellationToken ); // return Ok(result .ToDynamicObject()); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } /// /// Remove Many Items ... /// /// /// /// /// /// /// [HttpPost("RemoveMany")] public virtual async Task RemoveMany( [FromBody] XBaseRangeRequest request, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ) { // try { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotNull(request) .AddNotZeroChilds(request.Items) .ValidateGroupAsync(); // // Get Result ... await RepositoryService .RemoveRangeAsync( saveChanges: true, items: request.Items, softDelete: softDelete, cancellationToken: cancellationToken ); // return Ok(); } catch (Exception ex) { // var result = GetExceptionActionResult(ex); return result; } } #endregion #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Db\XDbContext.cs using System; using System.Linq; using Microsoft.EntityFrameworkCore; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Helpers; using xDataService.Providers; namespace xDataService.Db { /// /// Provide an abstraction layout arround DBContext ... /// Only Used on EFCore ... /// public abstract class XDbContext : DbContext { // #region Properties ... private readonly string database; private readonly XDataServiceConfiguration config; private readonly string[] dynamicEntityRegisterarsNames; private readonly XEntityRegisterarHandlerService dynamicEntityHandlers; #endregion // #region Entities ... // // Register Default and Base Entities ... #endregion // #region Constructor ... public XDbContext( string database, DbContextOptions options, XDataServiceConfiguration config, XEntityRegisterarHandlerService dynamicEntityHandlers, string[] dynamicEntityRegisterarsNames = null ) : base(options) { // try { Database.EnsureCreated(); Database.Migrate(); } catch { } // this.config = config; this.database = database; this.dynamicEntityHandlers = dynamicEntityHandlers; this.dynamicEntityRegisterarsNames = dynamicEntityRegisterarsNames; // // Handling DbSets of Dynamic Entities ... if (!dynamicEntityHandlers.IsNull()) { // // Configure XEntityRegisterarHandlerService ... dynamicEntityHandlers.HandleRegisteredEntities(); // // Loop through Entity Types ... foreach (var entityType in dynamicEntityHandlers.GetEntityTypes(dynamicEntityRegisterarsNames)) { // try { // // Use reflection to call Set() var method = typeof(XDbContext) .GetMethod(nameof(XDbContext.Set), Type.EmptyTypes) .MakeGenericMethod(entityType); if (!method.IsNull()) { method.Invoke(this, null); } } catch { } } } } #endregion /// /// Extract Current Database Configuration ... /// /// public XDataBaseConfiguration GetDatabaseConfiguration() { // XDataBaseConfiguration result = config.Databases.FirstOrDefault(db => string .Equals(db.Key, database, StringComparison.InvariantCultureIgnoreCase)).Value; // return result; } // #region Overrides ... // // Prepare Model Configs ... protected override void OnModelCreating(ModelBuilder modelBuilder) { // OnXModelCreating(modelBuilder); // // Automatically apply all IEntityTypeConfiguration in this assembly modelBuilder.ApplyConfigurationsFromAssembly(typeof(XDbContext).Assembly); // // Check Dynamic Registered Service is Exists or not ... if (!dynamicEntityHandlers.IsNull()) { // // Set Entity of Dynamically Registered Entities ... foreach (var entityType in dynamicEntityHandlers.GetEntityTypes(dynamicEntityRegisterarsNames)) { modelBuilder.Entity(entityType); } // // Configure Entity using Provided Registerar ... dynamicEntityHandlers .HandleApplyRegisteredEntitiesConfigurations(modelBuilder, dynamicEntityRegisterarsNames); } // // Since this class inherit from Identity Db Context, // we have to pass this to Building Identity Models ... base.OnModelCreating(modelBuilder); } // // Prepare Configuring ... protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // if (config.EnableDetailedErrors) { optionsBuilder.EnableDetailedErrors(); } // if (config.EnableSensitiveDataLogging) { optionsBuilder.EnableSensitiveDataLogging(); } // if (config.EnableTracking) { optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll); } else { optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } // OnXConfiguring(optionsBuilder); // base.OnConfiguring(optionsBuilder); } #endregion // #region Abstracts ... // public abstract void OnXModelCreating(ModelBuilder modelBuilder); // public abstract void OnXConfiguring(DbContextOptionsBuilder optionsBuilder); #endregion // #region Dynamic DbSet(s) ... public override DbSet Set() where TEntity : class { return base.Set(); } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Db\XUnitOfWorks.cs using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Db { /// /// Provide Unit Of Works Design Pattern for Db Transactions ... /// Only Used on EFCore ... /// /// public class XUnitOfWorks : IXUnitOfWorks where TDbContext : XDbContext { public TDbContext DbContext { get; } public XUnitOfWorks (TDbContext context) { this.DbContext = context; } public DbSet GetDbSet () where T : XBaseEntity { return DbContext.Set (); } /// /// Save Changes /// public int SaveChanges () { return DbContext.SaveChanges (); } /// /// Save Changes Async /// /// /// public async Task SaveChangesAsync ( CancellationToken cancellationToken = default ) { return await DbContext.SaveChangesAsync (cancellationToken); } public void Dispose () { DbContext.Dispose (); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\DI\XDIHelperExtension.cs using System; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using xCommons.Extensions; using xCommons.Helpers; using xDataService.Configuration; using xDataService.Constants; using xDataService.Extensions; using xDataService.Helpers; using xDataService.Models; using xDataService.Providers; using xExceptions.Constants; namespace xDataService.DI { public static partial class XDIHelperExtension { /// /// Retrive XDataService Configurations /// /// /// public static XDataServiceConfiguration GetXDataServiceConfiguration( this IConfiguration source ) { // var xDataServiceConfigSection = source .GetSection(ConfigurationNodeNames.DATA_SERVICE_NODE); var result = xDataServiceConfigSection.Get(); // // Reading Seeders ... if (!result.IsNull() && result.Databases.HasChild()) { // result .Databases .ToList() .ForEach(db => { // var seedItemsSectionName = $"{ConfigurationNodeNames.DATA_SERVICE_NODE}:{nameof(XDataServiceConfiguration.Databases)}:{db.Key}:{nameof(XDataBaseConfiguration.SeedItems)}"; var section = source.GetSection(seedItemsSectionName); var sectionJson = source.GetSectionAsJson(seedItemsSectionName); var sectionDict = sectionJson.FromJSON>>(); if (!sectionDict.IsNull() && sectionDict.Values.HasChild()) { // sectionDict .Keys .ToList() .ForEach(entity => { // // Setting Values to Result ... result.Databases[db.Key].SeedItems[entity] = sectionDict[entity]; }); } }); } // return result; } /// /// Register XDataService Configuration ... /// /// /// public static void AddXDataServiceConfiguration( this IServiceCollection source, IConfiguration configuration ) { // var config = configuration.GetXDataServiceConfiguration(); if (config.IsNullOrDefault()) { // Log("Configurations Not Founded ..."); XException.NotFound.Throw(); } // source.AddSingleton(config); } /// /// Register XDataService Configuration ... /// /// /// public static void AddXDataServiceConfiguration( this IServiceCollection source, XDataServiceConfiguration configuration ) { // if (configuration.IsNullOrDefault()) { // Log("Configurations Not Founded ..."); XException.NotFound.Throw(); } // source.AddSingleton(configuration); } /// /// Register a Data Base using Descriptor ... /// /// /// /// /// public static void AddXDatabase( this IServiceCollection source, IConfiguration configuration, XDatabaseDescriptor descriptor, ServiceLifetime lifeTime = ServiceLifetime.Scoped ) { // // Validate Database Descriptor ... var isValid = !descriptor.IsNullOrDefault() && !descriptor.Name.IsNullOrEmpty(); if (!isValid) { // Log("Invalid Database Descriptor ..."); return; } // // Check Service Collection Validation ... isValid = !source.IsNull() && !configuration.IsNull(); if (!isValid) { // Log("Invalid Service Provider or Configuration ..."); return; } // // Get Registere Data Service Configuration ... var xDataServiceConfiguration = source .GetRegisteredService(); isValid = !xDataServiceConfiguration.IsNullOrDefault(); if (!isValid) { // // Extract Configuration from Configuration ... xDataServiceConfiguration = configuration.GetXDataServiceConfiguration(); isValid = !xDataServiceConfiguration.IsNullOrDefault(); if (!isValid) { // Log("DataService Configuration not provided ..."); return; } // // Register Configuration in DI ... source.AddSingleton(xDataServiceConfiguration); } // // Check Data Service Configuration has Database ... isValid = !xDataServiceConfiguration.Databases.IsNullOrDefault() && xDataServiceConfiguration.Databases.HasChild() && xDataServiceConfiguration.Databases.Keys.Contains(descriptor.Name); if (!isValid) { // Log("Invalid Database Descriptor ..."); return; } // // Register Handler Service ... source.AddSingleton(); // // Configure Database Descriptor ... descriptor.Configure(source); // // Register Context ... if (!descriptor.Context.IsNull() && descriptor.Provider != XDbProviders.None && !descriptor.ConnectionString.IsNullOrEmpty()) { // try { // typeof(XDataServiceHelper).InvokeGenericMethod( methodName: "AddXDbContext", runtimeType: descriptor.Context, args: [ source, descriptor, lifeTime ] ); // Log($"DbContext: {descriptor.Name} Registered Successfully ..."); } catch (Exception ex) { Log($"DbContext: {descriptor.Name} Registration failed due {ex.Message} ..."); } } // // Register Repositories ... if (!descriptor.Repositories.IsNull() && descriptor.Repositories.HasChild()) { // descriptor.Repositories.ToList().ForEach(r => { // source.AddXRepository( descriptor: r, lifeTime: lifeTime ); }); } } public static void AddXRepository( this IServiceCollection source, XRepositoryDescriptor descriptor, ServiceLifetime lifeTime = ServiceLifetime.Scoped ) { // // Preparing Runtime Types ... Type[] runtimeTypes = descriptor.GetType().GenericTypeArguments; // try { // typeof(XDataServiceHelper).InvokeGenericMethod( methodName: "AddXRepository", runtimeTypes: runtimeTypes, args: [ source, descriptor, lifeTime ] ); // Log($"Repository of: {runtimeTypes[0]}, Registered Successfully ..."); } catch (Exception ex) { Log($"Repository of: {runtimeTypes[0]}, Registration failed due {ex.Message} ..."); } } public static void UseXDatabase( this IApplicationBuilder source, XDatabaseDescriptor descriptor, bool isDevelopmentEnvironment = false ) { // // Validate ... var isValid = !source.IsNull() && descriptor.IsValid(); if (!isValid) { // Log("Invalid Database Configuration ..."); XException.InvalidArgs.Throw(); } // // Check Repositories Exists ... isValid = descriptor.HasRepositories(); if (isValid) { // // Loop through Repositories ... descriptor.Repositories .ToList() .ForEach(r => { // source.UseXRepository( descriptor: r, isDevelopmentEnvironment: isDevelopmentEnvironment ); }); } } /// /// Use a Repository Middlewares by Providing it's Descriptor ... /// /// /// /// public static void UseXRepository( this IApplicationBuilder source, XRepositoryDescriptor descriptor, bool isDevelopmentEnvironment = false ) { // Log($"Start Using Repository of: {descriptor.Entity}"); // var withPlayground = false; if (isDevelopmentEnvironment) { withPlayground = true; } // // Create an Scope for Services Acces ... using (var scope = source.ApplicationServices.CreateScope()) { // // Inject XDataServiceConfiguration ForMake Sure DataService Registration ... var dataServiceConfiguration = scope.ServiceProvider.GetService(); var isValid = !dataServiceConfiguration.IsNullOrDefault(); if (isValid) { // // Check Seeder Exists ... // Execute Seeding Data Task if Exists ... isValid = descriptor.HasSeeder(); if (isValid) { // var seeder = (dynamic)scope.ServiceProvider.GetService(descriptor.SeederService); isValid = seeder != null; if (isValid) { // Log($"Start Seeding {descriptor.Entity} ..."); // // Seeding ... seeder .Seed() .GetAwaiter() .GetResult(); } } // // Check GraphQL Support ... isValid = descriptor.HasGraphSupport(); if (isValid) { // // Use WebSockets ... source.UseWebSockets(); // // Inject GraphQL Type Helper ... var helper = (dynamic)scope.ServiceProvider.GetService(descriptor.GraphTypeHelperService); isValid = helper != null; if (isValid) { // var graphPath = $"{helper.GetGraphQLPath()}"; var graphBasePath = $"{dataServiceConfiguration.GraphQLBasePath}"; typeof(XDataServiceHelper).InvokeGenericMethod( methodName: "UseXGraphQL", runtimeTypes: [ descriptor.Entity, descriptor.Key, descriptor.GraphType, descriptor.GraphTypeKey, descriptor.GraphQuery, descriptor.GraphTypeHelperService, descriptor.GraphTypeHelperImplementation, descriptor.GraphSchema ], args: [ source, graphBasePath, graphPath, withPlayground ] ); // Log($"Register GraphQL: {graphPath}"); } } } } } // #region Private ... /// /// a LogTag for xDataService ... /// private static string XLogTag = "xDataService"; /// /// print a log in Console ... /// /// private static void Log(string message) { Console.WriteLine($"{XLogTag} => {message}"); } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\DbContextOptionExtensions.cs using System; using Microsoft.EntityFrameworkCore.Infrastructure; using MySql.EntityFrameworkCore.Infrastructure; namespace xDataService.Extensions { public static class DbContextOptionExtensions { /// /// convert dynamic object to MySqlDbContextOptionBuilder ... /// Only Used in EFCore ... /// /// /// public static Action ToMySQLDbContextOptionsBuilder ( this Action source ) { return ((Action) source); } /// /// convert dynamic object to SqliteDbContextOptionBuilder ... /// Only Used in EFCore ... /// /// /// public static Action ToSqliteDbContextOptionsBuilder ( this Action source ) { return ((Action) source); } /// /// convert dynamic object to SqlServerDbContextOptionBuilder ... /// Only Used in EFCore ... /// /// /// public static Action ToSqlServerDbContextOptionsBuilder ( this Action source ) { return ((Action) source); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\EntityExtensions.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using xCommons.Extensions; using xModels.Base; namespace xDataService.Extensions { public static class EntityExtensions { /// /// return all values of an entity properties as a json string ... /// /// /// /// public static string GetPropValues (this T item) where T : XBaseEntity { // var props = item.GetType ().GetProperties (); var vals = props.Select (p => p.GetValue (item)); // return vals.ToJSON (); } /// /// check values of all properties of an Entity contains specific value or not ... /// /// /// /// /// public static bool PropValuesContains (this T item, string value) where T : XBaseEntity => item.GetPropValues () .ToNormalString () .Contains (value); /// /// Retrieve Default Column Map of specific Entity ... /// /// /// /// public static IDictionary>> GetDefaultColumnsMap (this T item) where T : XBaseEntity { // if (item.IsNull ()) { return null; } // var result = new Dictionary>> (); var props = item.GetType ().GetProperties (); // foreach (var prop in props) { result.Add ( prop.Name, t => t.GetType ().GetProperty (prop.Name).GetValue (t, null)); } // return result; } /// /// Check a Type is XBaseEntity or not ... /// /// /// public static bool IsXEntity(this Type source) { // var result = !source.IsNull(); if (!result) { return result; } // var baseType = source.BaseType; while(!baseType.IsNull() && baseType != typeof(object)) { // if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(XBaseEntity<>)) { result = true; break; } // baseType = baseType.BaseType; } // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\IQueryableExtensions.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; using xExceptions.Constants; using xModels.Base; using xModels.Dtos; namespace xDataService.Extensions { public static class IQueryableExtensions { /// /// Apply Search Filter on a Query /// /// /// /// /// public static IQueryable ApplyFilter( this IQueryable source, string filter ) where T : XBaseEntity { // // Apply Filter ... return source.Where(r => r.PropValuesContains(filter)); } /// /// Apply Search Filter on a Query /// /// /// /// /// public static async Task> ApplyFilterAsync( this IQueryable source, string filter ) where T : XBaseEntity { // // Where Clause ... Expression> whereClause = r => r .PropValuesContains(filter); // // Generate Where Function ... var whereFunc = whereClause.Compile(); // // Get Enumerable ... var enumerator = source .AsAsyncEnumerable(); // var result = new List(); await foreach (var entity in enumerator) { // var isApproved = whereFunc(entity); if (isApproved) { result.Add(entity); } } // return result.AsQueryable(); } /// /// Apply Search Filter on a Enumerable /// /// /// /// /// public static async Task> ApplyFilterAsync( this IEnumerable source, string filter ) where T : XBaseEntity { // // Where Clause ... Expression> whereClause = r => r .PropValuesContains(filter); // // Generate Where Function ... var whereFunc = whereClause.Compile(); // // Get Enumerable ... var enumerator = source .ToList() .AsQueryable(); // var result = new List(); foreach (var entity in enumerator) { // var isApproved = whereFunc(entity); if (isApproved) { result.Add(entity); } } // return result .AsEnumerable(); } /// /// Apply Search Filter on a Enumerable /// /// /// /// /// public static IEnumerable ApplyFilter( this IEnumerable source, string filter ) where T : class { // // Apply Filter ... return source.Where(r => r.PropValuesContains(filter)); } /// /// provide a way to Order an IQueryable by string FieldName ... /// /// /// /// /// public static IOrderedQueryable OrderBy( this IQueryable query, string propertyName ) { // var entityType = typeof(TSource); // // Create x => x.PropName var propertyInfo = entityType.GetProperty(propertyName); if (propertyInfo.IsNull()) { XException.InvalidArgs.Throw(); } // ParameterExpression arg = Expression.Parameter(entityType, "x"); MemberExpression property = Expression.Property(arg, propertyName); var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); // // Get System.Linq.Queryable.OrderBy() method. var enumarableType = typeof(System.Linq.Queryable); var method = enumarableType.GetMethods() .Where(m => m.Name == "OrderBy" && m.IsGenericMethodDefinition) .Where(m => { // var parameters = m.GetParameters().ToList(); // // Put more restriction here to ensure selecting the right overload return parameters.Count == 2; // overload that has 2 parameters }).Single(); // // The linq's OrderBy has two generic types, which provided here ... MethodInfo genericMethod = method .MakeGenericMethod(entityType, propertyInfo.PropertyType); /* Call query.OrderBy(selector), with query and selector: x=> x.PropName Note that we pass the selector as Expression to the method and we don't compile it. By doing so EF can extract "order by" columns and generate SQL for it. */ var newQuery = (IOrderedQueryable)genericMethod .Invoke(genericMethod, new object[] { query, selector }); // return newQuery; } /// /// provide a way to Order an IEnumerable by string FieldName ... /// /// /// /// /// public static IOrderedEnumerable OrderBy( this IEnumerable query, string propertyName ) { // var entityType = typeof(TSource); var propertyInfo = entityType.GetProperty(propertyName); if (propertyInfo.IsNull()) { XException.InvalidArgs.Throw(); } // return query.OrderBy(x => propertyInfo.GetValue(x, null)); } /// /// provide a way to Order an IQueryable by string FieldName ... /// /// /// /// /// public static IOrderedQueryable OrderByDescending( this IQueryable query, string propertyName ) { // var entityType = typeof(TSource); // // Create x => x.PropName var propertyInfo = entityType.GetProperty(propertyName); if (propertyInfo.IsNull()) { XException.InvalidArgs.Throw(); } // ParameterExpression arg = Expression.Parameter(entityType, "x"); MemberExpression property = Expression.Property(arg, propertyName); var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); // // Get System.Linq.Queryable.OrderBy() method. var enumarableType = typeof(System.Linq.Queryable); var method = enumarableType.GetMethods() .Where(m => m.Name == "OrderByDescending" && m.IsGenericMethodDefinition) .Where(m => { // var parameters = m.GetParameters().ToList(); // // Put more restriction here to ensure selecting the right overload return parameters.Count == 2; // overload that has 2 parameters }).Single(); // // The linq's OrderBy has two generic types, which provided here ... MethodInfo genericMethod = method .MakeGenericMethod(entityType, propertyInfo.PropertyType); /* Call query.OrderBy(selector), with query and selector: x=> x.PropName Note that we pass the selector as Expression to the method and we don't compile it. By doing so EF can extract "order by" columns and generate SQL for it. */ var newQuery = (IOrderedQueryable)genericMethod .Invoke(genericMethod, new object[] { query, selector }); // return newQuery; } /// /// provide a way to Order an IEnumerable by string FieldName ... /// /// /// /// /// public static IOrderedEnumerable OrderByDescending( this IEnumerable query, string propertyName ) { // var entityType = typeof(TSource); var propertyInfo = entityType.GetProperty(propertyName); if (propertyInfo.IsNull()) { XException.InvalidArgs.Throw(); } // return query.OrderByDescending(x => propertyInfo.GetValue(x, null)); } /// /// Apply Sorting on a query /// /// /// /// /// /// /// public static IQueryable ApplySorting( this IQueryable source, string sortBy, bool isAscending, IDictionary>> columnsMap = null ) where T : XBaseEntity { // if (columnsMap == null) { // columnsMap = source.FirstOrDefault() .GetDefaultColumnsMap(); // if (columnsMap == null) { return source; } } // // Validate SortBy ... var sortByItem = columnsMap.Keys .FirstOrDefault(p => p.ToNormalString() == sortBy.ToNormalString()); if (sortByItem.IsNullOrEmpty()) { return source; } // // Apply Sorting ... if (isAscending) { return source.OrderBy(sortByItem); } else { return source.OrderByDescending(sortByItem); } } /// /// Apply Sorting on a query /// /// /// /// /// /// /// public static IEnumerable ApplySorting( this IEnumerable source, string sortBy, bool isAscending, IDictionary>> columnsMap = null ) where T : XBaseEntity { // if (columnsMap == null) { // columnsMap = source.FirstOrDefault() .GetDefaultColumnsMap(); // if (columnsMap == null) { return source; } } // // Validate SortBy ... var sortByItem = columnsMap.Keys .FirstOrDefault(p => p.ToNormalString() == sortBy.ToNormalString()); if (sortByItem.IsNullOrEmpty()) { return source; } // // Apply Sorting ... if (isAscending) { return source.OrderBy(sortByItem); } else { return source.OrderByDescending(sortByItem); } } /// /// Apply Sorting on a Enumerable /// /// /// /// /// /// /// public static IEnumerable ApplySorting( this IEnumerable source, string sortBy, bool isAscending, IDictionary>> columnsMap = null ) where T : class { // if (columnsMap == null) { // columnsMap = source.FirstOrDefault() .GetDefaultColumnsMap(); // if (columnsMap == null) { return source; } } // // Validate SortBy ... var sortByItem = columnsMap.Keys .FirstOrDefault(p => p.ToNormalString() == sortBy.ToNormalString()); if (sortByItem.IsNullOrEmpty()) { return source; } // // Apply Sorting ... if (isAscending) { return source.OrderBy(sortByItem); } else { return source.OrderByDescending(sortByItem); } } /// /// Apply Paging on a qury /// /// /// /// /// /// public static IQueryable ApplyPaging( this IQueryable source, int? page, int? pageSize ) { // if (!page.HasValue || page <= 0) { page = 1; } // if (!pageSize.HasValue || pageSize <= 0 || pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) { pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE; } // var pageVal = page.GetValueOrDefault(); var pageSizeVal = pageSize.GetValueOrDefault(); // return source .Skip((pageVal - 1) * pageSizeVal) .Take(pageSizeVal); } /// /// Apply Paging on a Enumerable /// /// /// /// /// /// public static IEnumerable ApplyPaging( this IEnumerable source, int? page, int? pageSize ) { // if (!page.HasValue || page <= 0) { page = 1; } // if (!pageSize.HasValue || pageSize <= 0 || pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) { pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE; } // var pageVal = page.GetValueOrDefault(); var pageSizeVal = pageSize.GetValueOrDefault(); // return source .Skip((pageVal - 1) * pageSizeVal) .Take(pageSizeVal); } /// /// Count Query Pages based on Specified Total Number ... /// /// /// /// public static int CountPages(this XQuery source, int totalItems) { // int result = 0; // // Validate and Calculate ... if (!source.IsNull() && source.PageSize > 0 && totalItems > 0) { // result = totalItems / source.PageSize; if (totalItems % source.PageSize > 0) { result++; } } // return result; } /// /// Normalize an XQuery based on Data Service Configurations ... /// /// /// /// public static XQuery NormalizeQuery( this XQuery source, XDataServiceConfiguration configuration // ) { // if (source.IsNull()) { source = new XQuery(); } // // Page Size Normalization ... if (source.PageSize < configuration.PagingConfiguration.MinAvailablePageSize) { source.PageSize = configuration.PagingConfiguration.MinAvailablePageSize; } if (source.PageSize > configuration.PagingConfiguration.MaxAvailablePageSize) { source.PageSize = configuration.PagingConfiguration.MaxAvailablePageSize; } // return source; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XDatabaseDescriptorExtensions.cs using xCommons.Extensions; using xDataService.Constants; using xDataService.Models; namespace xDataService.Extensions { public static class XDatabaseDescriptorExtensions { /// /// Validate a Database Descriptor ... /// /// /// public static bool IsValid(this XDatabaseDescriptor source) { // var result = !source.IsNull() && !source.Name.IsNullOrEmpty(); // return result; } /// /// Chack a Descriptor Has Provider or not ... /// /// /// public static bool HasProvider(this XDatabaseDescriptor source) { // var result = source.IsValid() && source.Provider != XDbProviders.None; // return result; } /// /// Check a Descriptor Has EF Core Context or not ... /// /// /// public static bool HasContext(this XDatabaseDescriptor source) { // var result = source.IsValid() && source.HasProvider() && source.Provider != XDbProviders.MongoDB && !source.Context.IsNull(); // return result; } /// /// Check a Descriptor Has Repositories or not ... /// /// /// public static bool HasRepositories(this XDatabaseDescriptor source) { // var result = source.IsValid() && source.HasProvider() && !source.Repositories.IsNull() && source.Repositories.HasChild(); // return result; } /// /// Check a Descriptor Has MongoDB Convention Packs ... /// /// /// public static bool HasConventionPacks(this XDatabaseDescriptor source) { // var result = source.IsValid() && source.HasProvider() && source.Provider == XDbProviders.MongoDB && !source.ConventionPacks.IsNull(); // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XDataServiceConfigurationExtensions.cs using System.Linq; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; namespace xDataService.Extensions { public static class XDataServiceConfigurationExtensions { /// /// Extract Provider enum from Provider Type ... /// /// /// public static XDbProviders ToDbProvider (this string source) { // if (source.IsNullOrEmpty ()) { return XDbProviders.None; } // source = source.ToNormalString (); // var result = source == ProviderType.MySQL.ToNormalString () ? XDbProviders.MySQL : source == ProviderType.SQLite.ToNormalString () ? XDbProviders.SQLite : source == ProviderType.SQLServer.ToNormalString () ? XDbProviders.SQLServer : source == ProviderType.MongoDB.ToNormalString () ? XDbProviders.MongoDB : XDbProviders.None; // return result; } /// /// Retrieve Mongo URI from ConnectionString /// /// /// public static string GetMongoDbURI (this XDataBaseConfiguration source) { // var parts = source.GetConnectionParts (); var result = parts .Where (p => p.Trim ().StartsWith ("Uri=")) .FirstOrDefault (); result = result.Replace ("Uri=", "").Trim (); // return result; } /// /// Retrieve Mongo Database Name from Connaction string /// /// /// public static string GetMongoDbDatabase (this XDataBaseConfiguration source) { // var parts = source.GetConnectionParts (); var result = parts .Where (p => p.Trim ().StartsWith ("Database=")) .FirstOrDefault (); result = result.Replace ("Database=", "").Trim (); // return result; } // #region Private ... private static string[] GetConnectionParts (this XDataBaseConfiguration source) { // var result = source.ConnectionString.Split (';'); // return result; } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XGraphQLExtensions.cs using GraphQL; using GraphQL.Types; using xDataService.Constants; using xModels.Dtos; namespace xDataService.Extensions { public static class XGraphQLExtensions { public static TKey GetIdArgument (this IResolveFieldContext source) { return source.GetArgument (XGraphQLHelper.GetIdArgument().Name); } public static bool GetIgnoreSoftDeletedArgument (this IResolveFieldContext source) { return source.GetArgument (XGraphQLHelper.IgnoreSoftDeletedArgument.Name); } public static string GetSearchQueryArgument (this IResolveFieldContext source) { return source.GetArgument (XGraphQLHelper.SearchQueryArgument.Name); } public static XQuery GetQueryArgument (this IResolveFieldContext source) { return source.GetArgument (XGraphQLHelper.QueryArgument.Name); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XMongoDbExtensions.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Servers; using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; using MongoDB.Driver.Linq; using xDataService.Mongo; namespace xDataService.Extensions { public static class XMongoDbExtensions { public static Guid ToGuid (this ObjectId source) { // var bytes = source .ToByteArray () .Concat (new byte[] { 5, 5, 5, 5 }) .ToArray (); // var result = new Guid (bytes); // return result; } public static ObjectId ToObjectId (this Guid source) { // var bytes = source .ToByteArray () .Take (12) .ToArray (); // var result = new ObjectId (bytes); // return result; } public static IAsyncEnumerable ToAsyncEnumerable (this IAsyncCursorSource asyncCursorSource) { return new XAsyncEnumerableAdapter (asyncCursorSource); } public static async IAsyncEnumerable ToAsyncEnumerable (this IAsyncCursor source) { while (await source.MoveNextAsync ()) { foreach (var current in source.Current) { yield return current; } } } public static XMongoAsyncCursor ToAsyncCursor (this IQueryable source) { return new XMongoAsyncCursor (source); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XReferenceExtensions.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using xCommons.Extensions; using xDataService.Models; namespace xDataService.Extensions { public static class XReferenceExtensions { /// /// Converts an XReference to String Representation ... /// /// /// /// /// public static string ToXReferenceString( this XReference source, char? splitter = '_' ) { // var result = string.Empty; // // Normalize Splitter ... if (!splitter.HasValue) { splitter = '_'; } // if (!source.IsNullOrDefault() && source.Index >= 0 && !source.ReferencedTo.IsNull()) { result = $"{source.ProvidedFor}{splitter.Value}{source.ReferencedTo}{splitter.Value}{source.Index}"; } // return result; } /// /// Parse an String and Extract to XReference if it's Described ... /// /// /// /// /// public static XReference FromXReference( this string source, char? splitter = '_' ) { // XReference result = null; // // Normalize Splitter ... if (!splitter.HasValue) { splitter = '_'; } // if (!source.IsNullOrEmpty()) { // var parts = source.Split(splitter.Value); if (parts.Count() >= 3) { // T referencedTo; try { referencedTo = (T)Convert.ChangeType(parts[1], typeof(T)); } catch { referencedTo = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(parts[1]); } // // Parse String Parts ... result = new XReference { ReferencedTo = referencedTo, Index = (int)Convert.ChangeType(parts[2], typeof(int)), ProvidedFor = (string)Convert.ChangeType(parts[0], typeof(string)), }; } } // return result; } /// /// Converts a Collection of XReference to it's String Representation ... /// /// /// /// public static string ToXReferenceString(this IEnumerable> source) { // var result = string.Empty; // if (!source.IsNull() && source.HasChild()) { // var stringList = new List(); foreach (var s in source) { // var sr = ToXReferenceString(s); if (!sr.IsNullOrEmpty()) { stringList.Add(sr); } } // result = stringList.ToListString(); } // return result; } public static string ToXReferenceString(this ICollection> source) { // var result = source .AsEnumerable() .ToXReferenceString(); // return result; } public static string ToXReferenceString(this IList> source) { // var result = source .AsEnumerable() .ToXReferenceString(); // return result; } /// /// Parse an string to XReference Collection Representation ... /// /// /// /// public static IList> ParseXReferenceList(this string source) { // var result = new List>(); // if (!source.IsNullOrEmpty()) { // var stringList = source.ParseListString(); if (!stringList.IsNull() && stringList.HasChild()) { // foreach (var s in stringList) { // var sr = FromXReference(s); if (!sr.IsNullOrDefault()) { result.Add(sr); } } } } // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Extensions\XRepositoryDescriptorExtensions.cs using xCommons.Extensions; using xDataService.Db; using xDataService.Interfaces; using xDataService.Models; using xDataService.Providers; using xModels.Base; namespace xDataService.Extensions { public static class XRepositoryDescriptorExtensions { // #region Hasers ... /// /// Validate a Descriptor ... /// /// /// public static bool IsValid(this XRepositoryDescriptor source) { var result = !source.IsNull() && !source.Key.IsNull() && !source.Entity.IsNull(); // return result; } /// /// Check a Descriptor Has Events Service or not ... /// /// /// public static bool HasEvents(this XRepositoryDescriptor source) { // var result = source.IsValid() && !source.EventsService.IsNull() && !source.EventsImplementation.IsNull(); // return result; } /// /// Check a Descriptor Has EF Core Context or not ... /// /// /// public static bool HasContext(this XRepositoryDescriptor source) { // var result = source.IsValid() && !source.Context.IsNull(); // return result; } /// /// Check a Descriptor Has GraphQL Support or not ... /// /// /// public static bool HasGraphSupport(this XRepositoryDescriptor source) { // var result = source.IsValid() && source.HasRepository() && !source.GraphType.IsNull() && !source.GraphQuery.IsNull() && !source.GraphSchema.IsNull() && !source.GraphTypeKey.IsNull() && !source.GraphTypeHelperService.IsNull() && !source.GraphTypeHelperImplementation.IsNull(); // return result; } /// /// Check a Descriptor Has Key Generator Service or not ... /// /// /// public static bool HasKeyGenerator(this XRepositoryDescriptor source) { // var result = source.IsValid() && !source.KeyGeneratorService.IsNull() && !source.KeyGeneratorImplementation.IsNull(); // return result; } /// /// Check a Descriptor Has Repository Service or not ... /// /// /// public static bool HasRepository(this XRepositoryDescriptor source) { // var result = source.IsValid() && !source.RepositoryService.IsNull() && !source.RepositoryImplementation.IsNull(); // return result; } /// /// Check a Descriptor Has Seeder or not ... /// /// /// public static bool HasSeeder(this XRepositoryDescriptor source) { // var result = source.IsValid() && source.HasRepository() && !source.SeederService.IsNull() && !source.SeederImplementation.IsNull(); // return result; } #endregion // #region Builders ... public static XRepositoryDescriptor AddEntity( this XRepositoryDescriptor source ) where TEntity : XBaseEntity { // if (source.IsNull()) { source = new XRepositoryDescriptor(); } // source.Key = typeof(TKey); source.Entity = typeof(TEntity); // return source; } public static XRepositoryDescriptor AddEvents( this XRepositoryDescriptor source ) where TEntity : XBaseEntity where TEventsService : IXBaseRepositoryEvents where TEventsImplementation : XBaseRepositoryEvents { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.EventsService = typeof(TEventsService); source.EventsImplementation = typeof(TEventsImplementation); // return source; } public static XRepositoryDescriptor AddKeyGenerator( this XRepositoryDescriptor source ) where TEntity : XBaseEntity where TKeyGeneratorService : IXKeyGenerator where TKeyGeneratorImplementation : XKeyGenerator { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.KeyGeneratorService = typeof(TKeyGeneratorService); source.KeyGeneratorImplementation = typeof(TKeyGeneratorImplementation); // return source; } public static XRepositoryDescriptor AddSeeder( this XRepositoryDescriptor source ) where TEntity : XBaseEntity where TSeederService : IXBaseDbSeeder where TSeederImplementation : XBaseDbSeeder { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.SeederService = typeof(TSeederService); source.SeederImplementation = typeof(TSeederImplementation); // return source; } public static XRepositoryDescriptor AddEFRepository( this XRepositoryDescriptor source ) where TContext : XDbContext where TEntity : XBaseEntity where TRepositoryService : IXBaseRepository where TRepositoryImplementation : XBaseEFRepository { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.RepositoryService = typeof(TRepositoryService); source.RepositoryImplementation = typeof(TRepositoryImplementation); // return source; } public static XRepositoryDescriptor AddMongoRepository( this XRepositoryDescriptor source ) where TEntity : XBaseEntity where TRepositoryService : IXBaseRepository where TRepositoryImplementation : XBaseMongoRepository { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.RepositoryService = typeof(TRepositoryService); source.RepositoryImplementation = typeof(TRepositoryImplementation); // return source; } public static XRepositoryDescriptor AddInMemoryRepository( this XRepositoryDescriptor source ) where TEntity : XBaseEntity where TRepositoryService : IXBaseRepository where TRepositoryImplementation : XBaseInMemoryRepository { // if (source.IsNull()) { // source = new XRepositoryDescriptor(); source = source.AddEntity(); } // source.RepositoryService = typeof(TRepositoryService); source.RepositoryImplementation = typeof(TRepositoryImplementation); // return source; } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\GraphQL\XBaseGraphObjectType.cs using GraphQL.Types; using xModels.Base; namespace xDataService.GraphQL { /// /// Base Entity GraphType Object ... /// /// public abstract class XBaseGraphObjectType : ObjectGraphType where TEntity : XBaseEntity { public XBaseGraphObjectType () { // Name = $"{typeof(TEntity).Name}GraphType"; // Field (x => x.Id); Field (x => x.Deleted); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\GraphQL\XBaseGraphQLEventType.cs using GraphQL.Types; using xDataService.Models; using xModels.Base; namespace xDataService.GraphQL { public class XBaseGraphQLEventType : ObjectGraphType> where TGraphType : IGraphType where TEntity : XBaseEntity { public XBaseGraphQLEventType () { // Name = nameof (XBaseGraphQLEventType); // Field (x => x.Model, type : typeof (TGraphType)); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\GraphQL\XBaseGraphQLQuery.cs using System; using System.Linq.Expressions; using GraphQL.Types; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; using xDataService.Extensions; using xDataService.Interfaces; using xDataService.Models; using xModels.Base; namespace xDataService.GraphQL { public abstract class XBaseGraphQLQuery : ObjectGraphType, IXBaseGraphQLQuery where TEntity : XBaseEntity where TGraph : IGraphType where TGraphKey : IGraphType { // protected readonly XDataServiceConfiguration configuration; protected readonly IXBaseRepository repository; protected readonly IXBaseGraphQLTypeHelper helper; // public XBaseGraphQLQuery( XDataServiceConfiguration configuration, IXBaseRepository repository, IXBaseGraphQLTypeHelper helper ) { // this.helper = helper; this.repository = repository; this.configuration = configuration; // Name = GetType().Name; // #region Retrieve ... // // Get ... FieldAsync( name: helper.GetInQuerySingleName(), arguments: new QueryArguments( XGraphQLHelper.GetIdArgument(), XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async context => await repository .GetAsync( includeBuilder: null, id: context.GetIdArgument(), ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) .ToDynamicObject() ); // // GetAll ... FieldAsync>( name: helper.GetInQueryCollectionName(), arguments: new QueryArguments( XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async context => await repository .GetAllAsync( orderBuilder: null, includeBuilder: null, ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) .ToDynamicObject() ); // // FindOne ... FieldAsync( name: helper.GetFindOneName(), arguments: new QueryArguments( XGraphQLHelper.SearchQueryArgument, XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async (context) => { // var searchQuery = context.GetSearchQueryArgument(); Expression> whereClase = pe => pe .PropValuesContains(searchQuery); // return await repository .FindOneAsync( includeBuilder: null, predicate: whereClase, ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) .ToDynamicObject(); } ); // // FindMany ... FieldAsync>( name: helper.GetFindManyName(), arguments: new QueryArguments( XGraphQLHelper.SearchQueryArgument, XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async (context) => { // var searchQuery = context.GetSearchQueryArgument(); Expression> whereClase = pe => pe .PropValuesContains(searchQuery); // return await repository .FindManyAsync( orderBuilder: null, includeBuilder: null, predicate: whereClase, ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) .ToDynamicObject(); } ); // // Query ... FieldAsync>( name: helper.GetQueryName(), arguments: new QueryArguments( XGraphQLHelper.QueryArgument, XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async context => await repository .QueryAsync( predicate: null, orderBuilder: null, includeBuilder: null, query: context.GetQueryArgument(), ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) .ToDynamicObject() ); // // Count ... FieldAsync( name: helper.GetCountName(), arguments: new QueryArguments( XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async context => await repository .CountAsync( ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) ); // // Exists ... FieldAsync( name: helper.GetExistsName(), arguments: new QueryArguments( XGraphQLHelper.GetIdArgument(), XGraphQLHelper.IgnoreSoftDeletedArgument ), resolve: async context => await repository.IsExistsAsync( id: context.GetIdArgument(), ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument() ) ); #endregion } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\GraphQL\XBaseGraphQLSubscription.cs using System.Collections.Generic; using GraphQL.Resolvers; using GraphQL.Types; using xCommons.Extensions; using xDataService.Providers; using xDataService.Interfaces; using xDataService.Models; using xModels.Base; namespace xDataService.GraphQL { public abstract class XBaseGraphQLSubscription : ObjectGraphType where TGraph : IGraphType where TEntity : XBaseEntity { public XBaseGraphQLSubscription (IXBaseRepositoryEvents eventProvider = null) { // Name = GetType ().Name; // // Check if base repository patter registered ... if (!eventProvider.IsNull ()) { // // Add ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.AddEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver> ( context => context.Source as XBaseEventModel ), Subscriber = new EventStreamResolver> (context => { return eventProvider.OnAddObservable; }) }); // // Add Many ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.AddManyEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver>> ( context => context.Source as XBaseEventModel> ), Subscriber = new EventStreamResolver>> (context => { return eventProvider.OnAddManyObservable; }) }); // // Update ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.UpdateEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver> ( context => context.Source as XBaseEventModel ), Subscriber = new EventStreamResolver> (context => { return eventProvider.OnUpdateObservable; }) }); // // Update Mnay ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.UpdateManyEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver>> ( context => context.Source as XBaseEventModel> ), Subscriber = new EventStreamResolver>> (context => { return eventProvider.OnUpdateManyObservable; }) }); // // Remove ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.RemoveEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver> ( context => context.Source as XBaseEventModel ), Subscriber = new EventStreamResolver> (context => { return eventProvider.OnRemoveObservable; }) }); // // Remove Many ... AddField (new EventStreamFieldType { // Name = nameof (XBaseRepositoryEvents.RemoveManyEvent), Type = typeof (XBaseGraphQLEventType), Resolver = new FuncFieldResolver>> ( context => context.Source as XBaseEventModel> ), Subscriber = new EventStreamResolver>> (context => { return eventProvider.OnRemoveManyObservable; }) }); } } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\GraphQL\XBaseGraphQLTypeHelper.cs using xCommons.Extensions; using xDataService.Configuration; using xDataService.Interfaces; using xModels.Base; namespace xDataService.GraphQL { public abstract class XBaseGraphQLTypeHelper : IXBaseGraphQLTypeHelper where TEntity : XBaseEntity { // private readonly XDataServiceConfiguration configuration; // protected XBaseGraphQLTypeHelper( XDataServiceConfiguration configuration = null ) { this.configuration = configuration; } // public abstract string GetInQueryCollectionName(); public abstract string GetInQuerySingleName(); // public string GetFindOneName() { return $"find{GetInQuerySingleName().ToNormalString().Capitalize()}"; } public string GetFindManyName() { return $"find{GetInQueryCollectionName().ToNormalString().Capitalize()}"; } public string GetQueryName() { return $"query{GetInQueryCollectionName().ToNormalString().Capitalize()}"; } public string GetCountName() { return $"count{GetInQueryCollectionName().ToNormalString().Capitalize()}"; } public string GetExistsName() { return $"exists{GetInQuerySingleName().ToNormalString().Capitalize()}"; } public string GetGraphQLPath(string baseGraphPath = null) { // baseGraphPath = baseGraphPath.IsNullOrEmpty() ? configuration.IsNull() || configuration.GraphQLBasePath.IsNullOrEmpty() ? "" : configuration.GraphQLBasePath : baseGraphPath; // var basePath = baseGraphPath .EndsWith("/") ? baseGraphPath .Substring(0, baseGraphPath.Length - 1) : baseGraphPath; // return $"{basePath}/{GetInQueryCollectionName().ToNormalString()}"; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Helpers\XCursorHelper.cs using System; using System.Collections.Generic; using System.Linq; using xCommons.Extensions; namespace xDataService.Helpers { public partial class XCursorHelper { public static string ToCursor (T id) { // // Check Numbers ... if (id.ToString ().IsDigits ()) { return Convert .ToBase64String (BitConverter .GetBytes (Convert.ToInt32 (id)) ); } else // // Check Guid ... if (id.ToString ().IsGuid ()) { return Convert .ToBase64String (new Guid (id.ToString ()) .ToByteArray ()); } else // // Assume as String ... { return Convert .ToBase64String (id .ToString ().ToBytes ()); } } public static T FromCursor (string cursor) { // // Check Numbers ... var returnType = typeof (T); if (returnType == typeof (int) || returnType == typeof (long) || returnType == typeof (decimal)) { return Convert.ChangeType ((BitConverter .ToInt32 (Convert .FromBase64String (cursor), 0 )) .ToDynamicObject (), returnType); } else // // Check Guid ... if (returnType == typeof (Guid)) { return Convert.ChangeType ((new Guid ( Convert.FromBase64String (cursor) )) .ToDynamicObject (), returnType); } else // // Assume as String ... { return Convert.ChangeType (( Convert.FromBase64String (cursor) ) .ToDynamicObject (), returnType); } } public static (string firstCursor, string lastCursor) GetFirstAndLastCursor (IEnumerable ids) { // if (ids?.Any () != true) { return (null, null); } // var firstCursor = ToCursor (ids.First ()); var lastCursor = ToCursor (ids.Last ()); // return (firstCursor, lastCursor); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Helpers\XDataServiceHelper.cs using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using GraphQL; using GraphQL.Server; using GraphQL.Server.Ui.Playground; using GraphQL.Server.Ui.Voyager; using GraphQL.Types; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MySql.EntityFrameworkCore.Extensions; using xCommons.Extensions; using xDataService.Constants; using xDataService.Db; using xDataService.Extensions; using xDataService.GraphQL; using xDataService.Interfaces; using xDataService.Models; using xDataService.Providers; using xExceptions.Constants; using xModels.Base; namespace xDataService.Helpers { public static class XDataServiceHelper { /// /// Register DbContext ... /// /// /// /// /// public static void AddXDbContext( IServiceCollection source, XDatabaseDescriptor databaseDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TContext : XDbContext { // var isValid = databaseDescriptor.IsValid() && databaseDescriptor.HasProvider(); if (!isValid) { XException.InvalidConfiguration.Throw(); } // switch (databaseDescriptor.Provider) { // // MySQL ... case XDbProviders.MySQL: // source.AddEntityFrameworkMySQL(); source.AddDbContext(cfg => { // cfg.UseMySQL( databaseDescriptor.ConnectionString, databaseDescriptor.OptionsBuilder ); }, lifetime); break; // // SQLite ... case XDbProviders.SQLite: // source.AddEntityFrameworkSqlite(); source.AddDbContext(cfg => { // cfg.UseSqlite( databaseDescriptor.ConnectionString, databaseDescriptor.OptionsBuilder ); }, lifetime); break; // // Oracle ... case XDbProviders.Oracle: // source.AddEntityFrameworkOracle(); source.AddDbContext(cfg => { // cfg.UseOracle( databaseDescriptor.ConnectionString, databaseDescriptor.OptionsBuilder ); }, lifetime); break; // // SQLServer ... case XDbProviders.SQLServer: // source.AddEntityFrameworkSqlServer(); source.AddDbContext(cfg => { // cfg.UseSqlServer( databaseDescriptor.ConnectionString, databaseDescriptor.OptionsBuilder ); }, lifetime); break; // // Mongo DB ... case XDbProviders.MongoDB: // #region XBaseEntity Mappers ... // // Map ID as BsonId here ... BsonClassMap.RegisterClassMap>(cm => { // cm.AutoMap(); cm.MapIdMember(c => c.Id); }); BsonClassMap.RegisterClassMap>(cm => { // cm.AutoMap(); cm.MapIdMember(c => c.Id); }); BsonClassMap.RegisterClassMap>(cm => { // cm.AutoMap(); cm.MapIdMember(c => c.Id); }); BsonClassMap.RegisterClassMap>(cm => { // cm.AutoMap(); cm.MapIdMember(c => c.Id); }); #endregion // // Check Has Convention Packs ... isValid = databaseDescriptor.HasConventionPacks(); if (isValid) { // ConventionRegistry.Register( nameof( databaseDescriptor.ConventionPacks ), databaseDescriptor.ConventionPacks, type => !type.FullName .IsNullOrEmpty() ); } break; } // isValid = databaseDescriptor.Provider == XDbProviders.MySQL || databaseDescriptor.Provider == XDbProviders.SQLite || databaseDescriptor.Provider == XDbProviders.Oracle || databaseDescriptor.Provider == XDbProviders.SQLServer; if (isValid) { // AddXUnitOfWorks( source, lifetime ); } } // #region Repository ... /// /// Register Repository ... /// /// /// /// /// /// /// public static void AddXRepository( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TEntity : XBaseEntity { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TEntity : XBaseEntity where TKeyGeneratorService : IXKeyGenerator where TKeyGeneratorImplementation : XKeyGenerator { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TEntity : XBaseEntity where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation >( IServiceCollection source, XInMemoryRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseInMemoryRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TSeederService, TSeederImplementation >( IServiceCollection source, XInMemoryRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TSeederService : IXBaseDbSeeder where TSeederImplementation : XBaseDbSeeder where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseInMemoryRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } // // DbSeeder ... isValid = repositoryDescriptor.HasSeeder(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.SeederService, repositoryDescriptor.SeederImplementation, lifetime ) ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation >( IServiceCollection source, XMongoRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TRepositoryImplementation : XBaseMongoRepository where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TSeederService, TSeederImplementation >( IServiceCollection source, XMongoRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TSeederService : IXBaseDbSeeder where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TSeederImplementation : XBaseDbSeeder where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TRepositoryImplementation : XBaseMongoRepository where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } // // DbSeeder ... isValid = repositoryDescriptor.HasSeeder(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.SeederService, repositoryDescriptor.SeederImplementation, lifetime ) ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TContext >( IServiceCollection source, XEFRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TContext : XDbContext where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseEFRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } } /// /// Register Repository ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXRepository< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TContext, TSeederService, TSeederImplementation >( IServiceCollection source, XEFRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TContext : XDbContext where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TSeederService : IXBaseDbSeeder where TEventsService : IXBaseRepositoryEvents where TSeederImplementation : XBaseDbSeeder where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseEFRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // var isValid = repositoryDescriptor.IsValid(); if (!isValid) { return; } // // Register KeyGenerator ... isValid = repositoryDescriptor.HasKeyGenerator(); if (isValid) { // AddXKeyGenerator( source, repositoryDescriptor, lifetime ); } // // Register Events ... isValid = repositoryDescriptor.HasEvents(); if (isValid) { // AddXEvents( source, repositoryDescriptor, lifetime ); } // // Register Graph ... isValid = repositoryDescriptor.HasGraphSupport(); if (isValid) { // AddXGraphQL( source, repositoryDescriptor, lifetime ); } // // Register Repository ... isValid = repositoryDescriptor.HasRepository(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.RepositoryService, repositoryDescriptor.RepositoryImplementation, lifetime ) ); } // // DbSeeder ... isValid = repositoryDescriptor.HasSeeder(); if (isValid) { // source.Add( new ServiceDescriptor( repositoryDescriptor.SeederService, repositoryDescriptor.SeederImplementation, lifetime ) ); } } /// /// Use GraphQL ... /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static void UseXGraphQL< TEntity, TKey, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema >( IApplicationBuilder source, string graphBasePath, string graphPath, bool withPlayGround = false ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // source.UseGraphQL(graphPath); source.UseGraphQLWebSockets(); // if (withPlayGround) { // source.UseGraphQLPlayground(new GraphQLPlaygroundOptions { Path = "/ui/playground", GraphQLEndPoint = graphBasePath }); // source.UseGraphQLVoyager(new GraphQLVoyagerOptions { Path = "/ui/voyager", GraphQLEndPoint = graphBasePath }); } } #endregion // #region Entity Assembly Detector ... /// /// Extract Assemblies which Contains Entity ... /// /// public static List ExtractEntityAssemblies() { // var result = new List(); // var allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in allAssemblies) { // try { // bool hasEntity = assembly .GetExportedTypes() .Any(t => t.IsXEntity()); if (hasEntity) { result.Add(assembly); } } catch { } } // return result; } /// /// Register All Entities using Model Builder ... /// /// public static void RegisterAllEntities(this ModelBuilder modelBuilder) { // // Extract Entity Container Assemblies ... var entityAssemblies = ExtractEntityAssemblies(); foreach(var assembly in entityAssemblies) { modelBuilder.ApplyConfigurationsFromAssembly(assembly); } } #endregion // #region Private ... /// /// Register Unit of Works ... /// /// /// /// public static void AddXUnitOfWorks( IServiceCollection source, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TContext : XDbContext { // source.Add( new ServiceDescriptor( typeof(IXUnitOfWorks), typeof(XUnitOfWorks), lifetime ) ); } /// /// Register Key Generator Service ... /// /// /// /// /// /// /// /// /// public static void AddXKeyGenerator< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TEntity : XBaseEntity where TKeyGeneratorService : IXKeyGenerator where TKeyGeneratorImplementation : XKeyGenerator { // // Validate ... var isValid = !source.IsNull() && !repositoryDescriptor.IsNull() && !repositoryDescriptor.KeyGeneratorService.IsNull() && !repositoryDescriptor.KeyGeneratorImplementation.IsNull(); if (!isValid) { return; } // // Register ... source.Add( new ServiceDescriptor( repositoryDescriptor.KeyGeneratorService, repositoryDescriptor.KeyGeneratorImplementation, lifetime ) ); } /// /// Register Events Service ... /// /// /// /// /// /// /// /// /// public static void AddXEvents< TEntity, TKey, TEventsService, TEventsImplementation >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TEntity : XBaseEntity where TEventsService : IXBaseRepositoryEvents where TEventsImplementation : XBaseRepositoryEvents { // // Validate ... var isValid = !source.IsNull() && !repositoryDescriptor.IsNull() && !repositoryDescriptor.EventsService.IsNull() && !repositoryDescriptor.EventsImplementation.IsNull(); if (!isValid) { return; } // // Register ... source.Add( new ServiceDescriptor( repositoryDescriptor.EventsService, repositoryDescriptor.EventsImplementation, lifetime ) ); } /// /// Register GraphQL Service ... /// /// /// /// /// /// /// /// /// /// /// /// /// public static void AddXGraphQL< TEntity, TKey, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema >( IServiceCollection source, XRepositoryDescriptor repositoryDescriptor, ServiceLifetime lifetime = ServiceLifetime.Scoped ) where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // // Validate ... var isValid = !source.IsNull() && !repositoryDescriptor.IsNull() && !repositoryDescriptor.GraphType.IsNull() && !repositoryDescriptor.GraphQuery.IsNull() && !repositoryDescriptor.GraphSchema.IsNull() && !repositoryDescriptor.GraphTypeKey.IsNull() && !repositoryDescriptor.GraphTypeHelperService.IsNull() && !repositoryDescriptor.GraphTypeHelperImplementation.IsNull(); if (!isValid) { return; } // // Register Graph Type ... source.Add( new ServiceDescriptor( lifetime: lifetime, // ServiceLifetime.Singleton, serviceType: repositoryDescriptor.GraphType, implementationType: repositoryDescriptor.GraphType ) ); // // Register Graph Events ... source.Add( new ServiceDescriptor( lifetime: lifetime, // ServiceLifetime.Singleton, serviceType: typeof(XBaseGraphQLEventType), implementationType: typeof(XBaseGraphQLEventType) ) ); // // Register Graph Type Helper ... source.Add( new ServiceDescriptor( lifetime: ServiceLifetime.Singleton, serviceType: repositoryDescriptor.GraphTypeHelperService, implementationType: repositoryDescriptor.GraphTypeHelperImplementation ) ); // // Register Graph Query ... source.Add( new ServiceDescriptor( lifetime: lifetime, serviceType: repositoryDescriptor.GraphQuery, implementationType: repositoryDescriptor.GraphQuery ) ); // // Register Graph Schema ... source.Add( new ServiceDescriptor( lifetime: lifetime, serviceType: repositoryDescriptor.GraphSchema, implementationType: repositoryDescriptor.GraphSchema ) ); // source.AddScoped(); // // Register Graph Type Schema ... var builder = source.GetRegisteredService(); if (builder.IsNull()) { // Action options = x => { // x.EnableMetrics = true; x.UnhandledExceptionDelegate = context => { Console.WriteLine("XGraphQL Error: " + context.OriginalException.Message); }; }; builder = source.AddGraphQL(options) .AddNewtonsoftJson(deserializerSettings => { }, serializerSettings => { }) .AddWebSockets() .AddDataLoader() .AddGraphTypes(lifetime); } builder.AddGraphTypes( serviceLifetime: lifetime, typeFromAssembly: repositoryDescriptor.GraphSchema ); } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Helpers\XGraphQLHelper.cs using GraphQL.Types; using xDataService.Models; using xModels.Dtos; namespace xDataService.Constants { public static class XGraphQLHelper { public static QueryArgument GetIdArgument () where TKey : IGraphType { return new QueryArgument { Name = "id", Description = "the id of entity, which you want to retrieve ..." }; } public static QueryArgument IgnoreSoftDeletedArgument = new QueryArgument { Name = "ignoreSoftDeleteds", DefaultValue = true, Description = "determines result should ignore soft deleted items or not ..." }; public static QueryArgument SearchQueryArgument = new QueryArgument { Name = "searchQuery", Description = "the value which had to looking for ..." }; public static QueryArgument QueryArgument = new QueryArgument { Name = "query", DefaultValue = new XQuery (), Description = "determines query structure info for retrieving data ..." }; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseDbSeeder.cs using System.Threading.Tasks; using xDataService.Configuration; using xModels.Base; namespace xDataService.Interfaces { /// /// Db Seeder used to seed data on Database on startup time ... /// public interface IXBaseDbSeeder where TEntity : XBaseEntity { /// /// Holds Entity Name ... /// string Entity { get; } /// /// Holds Database Name ... /// string Database { get; } /// /// Repository Service for Data Manipulation ... /// IXBaseRepository Repository { get; } /// /// DataServiceConfiguration ... /// XDataServiceConfiguration DataServiceConfiguration { get; } /// /// do all seeding action by helping of Repositories here ... /// /// Task Seed(); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseGraphQLQuery.cs using GraphQL.Types; using xModels.Base; namespace xDataService.Interfaces { public interface IXBaseGraphQLQuery where TEntity : XBaseEntity where TGraph : IGraphType where TGraphKey : IGraphType { } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseGraphQLTypeHelper.cs using xModels.Base; namespace xDataService.Interfaces { public interface IXBaseGraphQLTypeHelper where TEntity : XBaseEntity { string GetInQuerySingleName(); string GetInQueryCollectionName(); string GetFindOneName(); string GetFindManyName(); string GetQueryName(); string GetCountName(); string GetExistsName(); string GetGraphQLPath(string baseGraphPath = null); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseReferencedProvider.cs using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using xDataService.Models; using xModels.Dtos; namespace xDataService.Interfaces { /// /// in Some Cases we have Entities Which Can Referenced for Specified /// Provider and Types ... /// this interface Globaly introduce all available Actions for those ... /// /// TKey: type of Provider Models Keys ... /// TModel: type of Dto which Referenced ... /// public interface IXBaseReferencedProvider { // #region Props ... /// /// Provider Identifier ... /// string Provider { get; } #endregion // #region Referenced Actions ... /// /// Get Specified Indexed Reference for Specific Provided ID ... /// /// /// /// /// Task GetReference( TKey providedForId, int forIndex = 0, CancellationToken cancellationToken = default ); /// /// Retrieve all Exists References of Specific Provided ID ... /// /// /// /// Task> GetAllReferences( TKey providedForId, CancellationToken cancellationToken = default ); /// /// Extract all Referencing Models for Specified Key ... /// /// /// /// Task>> GetAllReferencings( TKey providedForId, CancellationToken cancellationToken = default ); /// /// Count References ... /// /// /// /// Task CountReferences( TKey providedForId, CancellationToken cancellationToken = default ); /// /// Retrieve References of Specific Provided ID as Query ... /// /// /// /// /// Task> QueryReferences( XQuery query, TKey providedForId, CancellationToken cancellationToken = default ); /// /// Add Reference a Model to Specific Provided ID ... /// /// /// /// /// /// Task AddReference( TModel model, TKey providedForId, string connectionId = null, CancellationToken cancellationToken = default ); /// /// Add Reference a Model to Specific XRefence ... /// /// /// /// /// /// Task AddReference( TModel model, XReference reference, string connectionId = null, CancellationToken cancellationToken = default ); /// /// Remove Reference a Model for Specific Provided ID ... /// /// /// /// /// /// Task RemoveReference( TModel model, TKey providedForId, string connectionId = null, CancellationToken cancellationToken = default ); /// /// Remove Reference a Model for Specific XRefence ... /// /// /// /// /// /// Task RemoveReference( TModel model, XReference reference, string connectionId = null, CancellationToken cancellationToken = default ); /// /// Remove All References to Specified Key ... /// /// /// /// /// Task RemoveReferences( TKey providedForId, string connectionId = null, CancellationToken cancellationToken = default ); #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseRepository.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; using xModels.Base; using xModels.Dtos; namespace xDataService.Interfaces { public interface IXBaseRepository : IDisposable { } /// /// Base Repository Pattern Contracts in XDashboard's Data Service ... /// use for Data Manipulation ... /// /// /// public interface IXBaseRepository : IXBaseRepository where T : XBaseEntity { // #region Add ... /// /// add a new Entity ... /// /// /// /// /// Task AddAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// add or update an Entity (add if not exists/update if exists) ... /// /// /// /// /// Task AddOrUpdateAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// add a range of new Entities ... /// /// /// /// /// Task AddRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Update ... /// /// Update an Entity values ... /// /// /// /// /// /// Task UpdateAsync( TKey id, T item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// Update a range of Entities ... /// /// /// /// /// Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Remove ... /// /// remove an Entity by it's Id ... /// /// /// /// /// /// Task RemoveAsync( TKey id, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// remove an Entity ... /// /// /// /// /// /// Task RemoveAsync( T item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// remove a range of exists Entities ... /// /// /// /// /// /// Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Count ... /// /// count all exists Entities ... /// /// /// /// Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// Task PagesCountAsync( int pageSize, int? totalItems = null, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); #endregion // #region Retrieve ... /// /// retrieve whole items as queryable ... /// /// a flag for Tracking behaviour /// an Expression for Filter Items ... /// an Order Builder expression for Ordering Query ... /// an Include Builder expression for Including Navigation Properties ... /// IQueryable AsQueryable( bool asNoTracking = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ); /// /// retrieve an Entity by it's Id ... /// /// /// /// /// /// Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve all exists Entities ... /// /// /// /// /// /// Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve all exists Entities /// as Async Enumerable ... /// /// /// /// /// IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ); /// /// find an Entity by providing a Conditional Expression ... /// /// /// /// /// /// Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// find a collection of Entities by proving a Conditional Expression ... /// /// /// /// /// /// /// Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve Entities based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); #endregion // #region Exists ... /// /// Check an Entity exists or not ... /// /// /// /// /// Task IsExistsAsync( TKey id, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); #endregion // #region Unit Of Work ... /// /// Save all unsaved Transactions on DbContext ... /// used fo Unit Of Works Design Pattern ... /// /// /// Task SaveChangesAsync( CancellationToken cancellationToken = default ); #endregion // #region Key ... /// /// Retrieve Key of Entity ... /// /// /// TKey GetKey(T item); /// /// Set Key of Entity ... /// /// /// void SetKey( ref T item, TKey id ); /// /// Handle Checking Key ... /// /// /// /// Task HandleKeyAsync( T item, CancellationToken cancellationToken = default ); #endregion // #region Detach ... /// /// Detach an Entity ... /// /// void Detach(T item); /// /// Detach an Enumerable of Entities ... /// /// void Detach(IEnumerable items); /// /// Detach a Query Result of Entity ... /// /// void Detach(XQueryResult query); #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseRepositoryController.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Query; using xModels.Base; using xModels.Dtos; namespace xDataService.Interfaces { /// /// an Interface for Base Repository Actions Providing Using Controllers ... /// /// /// /// public interface IXBaseRepositoryController where TEntity : XBaseEntity { // IXBaseRepository Repository { get; } Func, IOrderedQueryable> DefaultOrderBuilder { get; } Func, IIncludableQueryable> DefaultIncludeBuilder { get; } // #region Add ... Task> Add( [FromBody] TEntity item, CancellationToken cancellationToken = default ); Task> AddOrUpdate( [FromBody] TEntity item, CancellationToken cancellationToken = default ); Task AddMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ); #endregion // #region Retrieve ... Task> Get( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> GetAll( [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task> FindOne( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> FindMany( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> Query( [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); #endregion // #region Update ... Task> Update( [FromRoute] TKey id, [FromBody] TEntity item, CancellationToken cancellationToken = default ); Task> UpdateMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ); #endregion // #region Exists ... Task> IsExists( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); #endregion // #region Remove ... Task> Remove( [FromRoute] TKey id, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ); Task RemoveMany( [FromBody] XBaseRangeRequest request, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ); #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseRepositoryEvents.cs using System; using System.Collections.Generic; using xDataService.Models; namespace xDataService.Interfaces { public interface IXBaseRepositoryEvents { // void AddEvent (XBaseEventModel model); void UpdateEvent (XBaseEventModel model); void RemoveEvent (XBaseEventModel model); // void AddManyEvent (XBaseEventModel> model); void UpdateManyEvent (XBaseEventModel> model); void RemoveManyEvent (XBaseEventModel> model); // IObservable> OnAddObservable { get; } IObservable> OnUpdateObservable { get; } IObservable> OnRemoveObservable { get; } // IObservable>> OnAddManyObservable { get; } IObservable>> OnUpdateManyObservable { get; } IObservable>> OnRemoveManyObservable { get; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseRepositoryService.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using AutoMapper; using Microsoft.EntityFrameworkCore.Query; using xModels.Base; using xModels.Dtos; namespace xDataService.Interfaces { /// /// an Interface for Manipulating Data Using Services based on Dto Mapping ... /// /// /// /// public interface IXBaseRepositoryService : IDisposable where TEntity : XBaseEntity where TDto : XBaseEntityDto { // #region Properties ... /// /// Mapper Instance ... /// IMapper Mapper { get; } /// /// Repository Implementation for Data Manipulations ... /// IXBaseRepository Repository { get; } /// /// 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 ... /// MapperConfiguration MapperConfiguration { get; } #endregion // #region Actions ... // #region Add ... /// /// add a new Dto ... /// /// /// /// /// Task AddAsync( TDto item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// add or update a Dto (add if not exists/update if exists) ... /// /// /// /// /// Task AddOrUpdateAsync( TDto item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// add a range of new Dtos ... /// /// /// /// /// Task AddRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Update ... /// /// Update an Dto values ... /// /// /// /// /// /// Task UpdateAsync( TKey id, TDto item, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// Update a range of Dtos ... /// /// /// /// /// Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Remove ... /// /// remove an Dto by it's Id ... /// /// /// /// /// /// Task RemoveAsync( TKey id, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// remove an Dto ... /// /// /// /// /// /// Task RemoveAsync( TDto item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); /// /// remove a range of exists Dtos ... /// /// /// /// /// /// Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ); #endregion // #region Count ... /// /// count all exists Dtos ... /// /// /// /// Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// Task PagesCountAsync( int pageSize, int? totalItems = null, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); #endregion // #region Retrieve ... /// /// retrieve an Dto by it's Id ... /// /// /// /// /// /// Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve all exists Dtos ... /// /// /// /// /// /// Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve all exists Dtos /// as Async Enumerable ... /// /// /// /// /// /// IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// find an Dto by providing a Conditional Expression ... /// /// /// /// /// /// Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// find a collection of Dtos by proving a Conditional Expression ... /// /// /// /// /// /// /// Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); /// /// retrieve Dtos based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ); #endregion // #region Exists ... /// /// Check a Dto exists or not ... /// /// /// /// /// Task IsExistsAsync( TKey id, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ); #endregion #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXBaseServiceController.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Query; using xModels.Base; using xModels.Dtos; namespace xDataService.Interfaces { /// /// an Interface for Base RepositoryService Actions Providing Using Controllers ... /// /// /// /// public interface IXBaseServiceController where TEntity : XBaseEntity where TDto : XBaseEntityDto { // IXBaseRepositoryService RepositoryService { get; } Func, IOrderedQueryable> DefaultOrderBuilder { get; } Func, IIncludableQueryable> DefaultIncludeBuilder { get; } // #region Add ... Task> Add( TDto item, CancellationToken cancellationToken = default ); Task> AddOrUpdate( TDto item, CancellationToken cancellationToken = default ); Task AddMany( XBaseRangeRequest request, CancellationToken cancellationToken = default ); #endregion // #region Retrieve ... Task> Get( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> GetAll( [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task> FindOne( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> FindMany( [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); Task>> Query( [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool useDefaultOrders = false, [FromQuery] bool useDefaultIncludes = false, CancellationToken cancellationToken = default ); #endregion // #region Update ... Task> Update( [FromRoute] TKey id, [FromBody] TDto item, CancellationToken cancellationToken = default ); Task> UpdateMany( [FromBody] XBaseRangeRequest request, CancellationToken cancellationToken = default ); #endregion // #region Exists ... Task> IsExists( [FromRoute] TKey id, [FromQuery] bool ignoreSoftDeletedss = true, CancellationToken cancellationToken = default ); #endregion // #region Remove ... Task> Remove( [FromRoute] TKey id, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ); Task RemoveMany( [FromBody] XBaseRangeRequest request, [FromQuery] bool softDelete = true, CancellationToken cancellationToken = default ); #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXDatabaseDescriptor.cs using System; using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson.Serialization.Conventions; using xDataService.Configuration; using xDataService.Constants; using xDataService.Db; using xDataService.Models; namespace xDataService.Interfaces { /// /// Data Base Descriptor ... /// public interface IXDatabaseDescriptor { // #region Props ... /// /// Database Name ... /// /// string Name { get; set; } /// /// Database Provider ... /// /// XDbProviders Provider { get; set; } /// /// Db Context Type ... /// /// Type Context { get; set; } /// /// Database Connecion String ... /// /// string ConnectionString { get; set; } /// /// Data Service Configuration ... /// /// XDataBaseConfiguration Configuration { get; set; } /// /// Repositories Descriptions ... /// /// IList Repositories { get; set; } /// /// Mongo Convention Packs ... /// ConventionPack ConventionPacks { get; set; } /// /// DbContext Options Builder ... /// /// Action OptionsBuilder { get; set; } #endregion // #region Configure ... /// /// Configure Database Descriptor using Registered Services ... /// /// void Configure( IServiceCollection services ); /// /// Configure Database Descriptor using IConfiguration ... /// /// void Configure( IConfiguration configuration ); /// /// Configure Database Descriptor using Database Configuration ... /// /// void Configure( XDataBaseConfiguration configuration ); /// /// Configure Database Descriptor using Provider and Connection String ... /// /// /// void Configure( XDbProviders provider, string connectionString ); #endregion } /// /// Data Base Descriptor ... /// /// public interface IXDatabaseDescriptor : IXDatabaseDescriptor where TContext : XDbContext { } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXEntityRegisterar.cs using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using xModels.Base; namespace xDataService.Interfaces { /// /// an Interface to Intruduce Entities for Dynamic Registration ... /// public interface IXEntityRegisterar { /// /// Database Name ... /// string Name { get; } /// /// Returns all entity types this plugin wants registered in the DbContext /// IEnumerable GetEntityTypes(); /// /// Optional: Apply additional per-entity configuration /// void ConfigureEntities(ModelBuilder modelBuilder); /// /// Add XDataService Based Entity to List ... /// /// /// void AddEntity() where TEntity : XBaseEntity; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXKeyGenerator.cs using System.Threading; using System.Threading.Tasks; using xModels.Base; namespace xDataService.Interfaces { /// /// Typed Base Key Generator ... /// /// /// public interface IXKeyGenerator where TEntity : XBaseEntity { bool IsEmpty(TKey id); Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXSequentialGuid.cs using System; namespace xDataService.Interfaces { /// /// this service provide Sequential GUID mechanism for Entity Ids ... /// public interface IXSequentialGuid { Guid GetCurrentGuid (); Guid Next (); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Interfaces\IXUnitOfWorks.cs using System; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using xDataService.Db; using xModels.Base; namespace xDataService.Interfaces { /// /// Provide Unit Of Works Design Pattern for Db Transactions ... /// Only Used on EFCore ... /// /// public interface IXUnitOfWorks : IDisposable where TDbContext : XDbContext { TDbContext DbContext { get; } DbSet GetDbSet () where T : XBaseEntity; int SaveChanges (); Task SaveChangesAsync ( CancellationToken cancellationToken = default ); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XBaseEventModel.cs namespace xDataService.Models { /// /// Pass Data on Repository Events ... /// /// public class XBaseEventModel { public T Model { get; set; } public XBaseEventModel (T model) { Model = model; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XDatabaseDescriptor.cs using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson.Serialization.Conventions; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; using xDataService.Db; using xDataService.DI; using xDataService.Interfaces; namespace xDataService.Models { /// /// Data Base Descriptor ... /// public abstract class XDatabaseDescriptor : IXDatabaseDescriptor { // #region Props ... /// /// Database Name ... /// /// public virtual string Name { get; set; } /// /// Database Provider ... /// /// public virtual XDbProviders Provider { get; set; } /// /// Db Context... /// /// public virtual Type Context { get; set; } = null; /// /// Database Connecion String ... /// /// public virtual string ConnectionString { get; set; } /// /// Data Service Configuration ... /// /// public virtual XDataBaseConfiguration Configuration { get; set; } /// /// Repositories Descriptions ... /// /// public virtual IList Repositories { get; set; } = null; /// /// Mongo Convention Packs ... /// public ConventionPack ConventionPacks { get; set; } = null; /// /// DbContext Options Builder ... /// /// public Action OptionsBuilder { get; set; } = null; #endregion // #region Constructor ... /// /// Constructor of Descriptor ... /// /// /// /// public XDatabaseDescriptor( string name, IList repositories = null ) { // Name = name; Repositories = repositories; } #endregion // #region Configure ... /// /// Configure Database Descriptor using Registered Services ... /// /// public void Configure( IServiceCollection services ) { // bool isValid = !Name.IsNullOrEmpty(); if (!isValid) { return; } // var xDataServiceConfiguration = services.GetRegisteredService(); isValid = !xDataServiceConfiguration.IsNullOrDefault() && xDataServiceConfiguration.Databases.HasChild() && xDataServiceConfiguration.Databases.Keys.Any(k => k == Name); if (!isValid) { return; } // var database = xDataServiceConfiguration.Databases[Name]; isValid = !database.IsNullOrDefault(); if (!isValid) { return; } // Configure(database); } /// /// Configure Database Descriptor using IConfiguration ... /// /// public void Configure( IConfiguration configuration ) { // bool isValid = !Name.IsNullOrEmpty(); if (!isValid) { return; } // var xDataServiceConfiguration = configuration.GetXDataServiceConfiguration(); isValid = !xDataServiceConfiguration.IsNullOrDefault() && xDataServiceConfiguration.Databases.HasChild() && xDataServiceConfiguration.Databases.Keys.Any(k => k == Name); if (!isValid) { return; } // var database = xDataServiceConfiguration.Databases[Name]; isValid = !database.IsNullOrDefault(); if (!isValid) { return; } // Configure(database); } /// /// Configure Database Descriptor using Database Configuration ... /// /// public void Configure( XDataBaseConfiguration configuration ) { // Configuration = configuration; Provider = configuration.Provider; ConnectionString = configuration.ConnectionString; } /// /// Configure Database Descriptor using Provider and Connection String ... /// /// /// public void Configure( XDbProviders provider, string connectionString ) { // Provider = provider; ConnectionString = connectionString; Configuration = new XDataBaseConfiguration { Provider = provider, ConnectionString = connectionString }; } #endregion } /// /// Data Base Descriptor ... /// /// public abstract class XDatabaseDescriptor : XDatabaseDescriptor, IXDatabaseDescriptor where TContext : XDbContext { /// /// Constructor of Descriptor ... /// /// /// /// /// public XDatabaseDescriptor( string name, IList repositories = null ) : base( name: name, repositories: repositories ) { Context = typeof(TContext); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XGraphQueryResult.cs using GraphQL.Types; using xModels.Dtos; namespace xDataService.Models { public class XGraphQueryResult : ObjectGraphType> where TGraph : IGraphType { public XGraphQueryResult () { // Name = $"{typeof(TGraph).Name}QueryResult"; // Field> (nameof (XQueryResult.Items)); Field (x => x.Page); Field (x => x.PageSize); Field (x => x.TotalPages); Field (x => x.TotalFilteredItems); Field (x => x.TotalItems); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XGraphQueryType.cs using GraphQL.Types; using xModels.Dtos; namespace xDataService.Models { public class XGraphQueryType : InputObjectGraphType { public XGraphQueryType () { // Name = "query"; // Field (x => x.Filter); Field (x => x.ContainsDetail); Field (x => x.SortBy); Field (x => x.IsAscending); Field (x => x.Page); Field (x => x.PageSize); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XReference.cs namespace xDataService.Models { public class XReference { public int Index { get; set; } public T ReferencedTo { get; set; } public string ProvidedFor { get; set; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Models\XRepositoryDescriptor.cs using System; using GraphQL.Types; using xDataService.Db; using xDataService.GraphQL; using xDataService.Interfaces; using xDataService.Providers; using xModels.Base; namespace xDataService.Models { /// /// a Global non Generic Repository Descriptor ... /// public class XRepositoryDescriptor { /// /// Entity Key Type ... /// /// public Type Key { get; set; } = null; /// /// Entity Type ... /// /// public Type Entity { get; set; } = null; /// /// Context Type ... /// /// public Type Context { get; set; } = null; /// /// Graph Type Key ... /// /// public Type GraphTypeKey { get; set; } = null; /// /// Graph Type ... /// /// public Type GraphType { get; set; } = null; /// /// Entity Type GraphQL Schema ... /// /// public Type GraphSchema { get; set; } = null; /// /// Entity GraphQL Type Helper ... /// /// public Type GraphTypeHelperService { get; set; } = null; /// /// Entity GraphQL Type Helper ... /// /// public Type GraphTypeHelperImplementation { get; set; } = null; /// /// Entity GrapQL Query ... /// /// public Type GraphQuery { get; set; } = null; /// /// Repository Event Provider ... /// /// public Type EventsService { get; set; } = null; /// /// Repository Event Provider ... /// /// public Type EventsImplementation { get; set; } = null; /// /// Repository Key Generator for Entity ... /// /// public Type KeyGeneratorService { get; set; } = null; /// /// Repository Key Generator for Entity ... /// /// public Type KeyGeneratorImplementation { get; set; } = null; /// /// Repository Data Access Design Pattern ... /// /// public Type RepositoryService { get; set; } = null; /// /// Repository Data Access Design Pattern ... /// /// public Type RepositoryImplementation { get; set; } = null; /// /// Database Data Seeder ... /// public Type SeederService { get; set; } = null; /// /// Database Data Seeder ... /// public Type SeederImplementation { get; set; } = null; } /// /// a Repository Descriptor ... /// /// /// public class XRepositoryDescriptor : XRepositoryDescriptor where TEntity : XBaseEntity { public XRepositoryDescriptor() : base() { // Key = typeof(TKey); Entity = typeof(TEntity); } } /// /// a Repository Descriptor ... /// public class XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation > : XRepositoryDescriptor where TEntity : XBaseEntity where TKeyGeneratorService : IXKeyGenerator where TKeyGeneratorImplementation : XKeyGenerator { public XRepositoryDescriptor() : base() { // KeyGeneratorService = typeof(TKeyGeneratorService); KeyGeneratorImplementation = typeof(TKeyGeneratorImplementation); } } /// /// a Repository Descriptor ... /// public class XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation > where TEntity : XBaseEntity where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator { public XRepositoryDescriptor() : base() { // EventsService = typeof(TEventsService); EventsImplementation = typeof(TEventsImplementation); } } /// /// a Repository Descriptor ... /// public class XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation > where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XRepositoryDescriptor() : base() { // GraphType = typeof(TGraph); GraphTypeKey = typeof(TGraphKey); GraphQuery = typeof(TGraphQuery); GraphSchema = typeof(TGraphSchema); GraphTypeHelperService = typeof(TGraphTypeHelperService); GraphTypeHelperImplementation = typeof(TGraphTypeHelperImplementation); } } /// /// a Repository Descriptor ... /// public class XInMemoryRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TRepositoryImplementation : XBaseInMemoryRepository where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XInMemoryRepositoryDescriptor() : base() { // RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } /// /// a Repository Descriptor ... /// public class XInMemoryRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TSeederService, TSeederImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TSeederService : IXBaseDbSeeder where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TSeederImplementation : XBaseDbSeeder where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TRepositoryImplementation : XBaseInMemoryRepository where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XInMemoryRepositoryDescriptor() : base() { // SeederService = typeof(TSeederService); SeederImplementation = typeof(TSeederImplementation); // RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } /// /// a Repository Descriptor ... /// public class XMongoRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TRepositoryImplementation : XBaseMongoRepository where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XMongoRepositoryDescriptor() : base() { // RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } /// /// a Repository Descriptor ... /// public class XMongoRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TSeederService, TSeederImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TSeederService : IXBaseDbSeeder where TEventsService : IXBaseRepositoryEvents where TSeederImplementation : XBaseDbSeeder where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TRepositoryImplementation : XBaseMongoRepository where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XMongoRepositoryDescriptor() : base() { // SeederService = typeof(TSeederService); SeederImplementation = typeof(TSeederImplementation); // RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } /// /// a Repository Descriptor ... /// public class XEFRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TContext > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TContext : XDbContext where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TEventsService : IXBaseRepositoryEvents where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseEFRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XEFRepositoryDescriptor() : base() { // Context = typeof(TContext); RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } /// /// a Repository Descriptor ... /// public class XEFRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema, TRepositoryService, TRepositoryImplementation, TContext, TSeederService, TSeederImplementation > : XRepositoryDescriptor< TEntity, TKey, TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema where TContext : XDbContext where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType where TSeederService : IXBaseDbSeeder where TEventsService : IXBaseRepositoryEvents where TSeederImplementation : XBaseDbSeeder where TKeyGeneratorService : IXKeyGenerator where TRepositoryService : IXBaseRepository where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery where TRepositoryImplementation : XBaseEFRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { public XEFRepositoryDescriptor() : base() { // SeederService = typeof(TSeederService); SeederImplementation = typeof(TSeederImplementation); // Context = typeof(TContext); RepositoryService = typeof(TRepositoryService); RepositoryImplementation = typeof(TRepositoryImplementation); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Mongo\XAsyncEnumerableAdapter.cs using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; namespace xDataService.Mongo { public class XAsyncEnumerableAdapter : IAsyncEnumerable { // private readonly IAsyncCursorSource asyncCursorSource; // public XAsyncEnumerableAdapter (IAsyncCursorSource asyncCursorSource) { this.asyncCursorSource = asyncCursorSource; } // public IAsyncEnumerator GetAsyncEnumerator (CancellationToken cancellationToken) => new XAsyncEnumeratorAdapter (asyncCursorSource, cancellationToken); } public class XAsyncEnumeratorAdapter : IAsyncEnumerator { private readonly IAsyncCursorSource asyncCursorSource; private readonly CancellationToken cancellationToken; private IAsyncCursor asyncCursor; private IEnumerator batchEnumerator; public T Current => batchEnumerator.Current; public XAsyncEnumeratorAdapter ( IAsyncCursorSource asyncCursorSource, CancellationToken cancellationToken ) { // this.asyncCursorSource = asyncCursorSource; this.cancellationToken = cancellationToken; } public async ValueTask MoveNextAsync () { // if (asyncCursor == null) { asyncCursor = await asyncCursorSource .ToCursorAsync (cancellationToken); } // if (batchEnumerator != null && batchEnumerator.MoveNext ()) { return true; } // if (asyncCursor != null && await asyncCursor.MoveNextAsync (cancellationToken)) { // batchEnumerator?.Dispose (); batchEnumerator = asyncCursor.Current.GetEnumerator (); // return batchEnumerator.MoveNext (); } // return false; } public async ValueTask DisposeAsync () { // await Task.CompletedTask; asyncCursor?.Dispose (); asyncCursor = null; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Mongo\XMongoAsyncCursor.cs using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; namespace xDataService.Mongo { public class XMongoAsyncCursor : IAsyncCursor { public IEnumerable Current { get; } private IEnumerator CurrentEnumerator { get; } public XMongoAsyncCursor (IEnumerable source) { this.Current = source; this.CurrentEnumerator = source.GetEnumerator (); } public void Dispose () { CurrentEnumerator.Dispose (); } public bool MoveNext (CancellationToken cancellationToken = default) { return CurrentEnumerator.MoveNext (); } public Task MoveNextAsync (CancellationToken cancellationToken = default) { return Task.Run ( () => CurrentEnumerator.MoveNext (), cancellationToken : cancellationToken ); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Mongo\XMongoQueryable.cs using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; using xModels.Base; namespace xDataService.Mongo { public class XMongoQueryable : IMongoQueryable where TEntity : XBaseEntity { private readonly IMongoCollection collection; public Type ElementType { get; } public IQueryable Items { get; } public Expression Expression { get; } public IQueryProvider Provider { get; } public XMongoQueryable ( IQueryable items, IMongoCollection collection ) { // this.Items = items; this.collection = collection; // Provider = items.Provider; Expression = items.Expression; ElementType = items.ElementType; } public IEnumerator GetEnumerator () { return Items.GetEnumerator (); } public QueryableExecutionModel GetExecutionModel () { return collection.AsQueryable ().GetExecutionModel (); } public IAsyncCursor ToCursor (CancellationToken cancellationToken = default) { return new XMongoAsyncCursor (Items); } public Task> ToCursorAsync (CancellationToken cancellationToken = default) { return Task.Run (() => new XMongoAsyncCursor (Items) as IAsyncCursor); } IEnumerator IEnumerable.GetEnumerator () { return Items.GetEnumerator (); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Mongo\XMongoReadPreferenceResolver.cs using MongoDB.Driver; namespace xDataService.Mongo { public static class XMongoReadPreferenceResolver { public static ReadPreference GetEffectiveReadPreference ( IClientSessionHandle session, ReadPreference explicitReadPreference, ReadPreference defaultReadPreference) { if (explicitReadPreference != null) { return explicitReadPreference; } if (session.IsInTransaction) { var transactionReadPreference = session.WrappedCoreSession.CurrentTransaction.TransactionOptions.ReadPreference; if (transactionReadPreference != null) { return transactionReadPreference; } } return defaultReadPreference ?? ReadPreference.Primary; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseDbSeeder.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Providers { public abstract class XBaseDbSeeder : IXBaseDbSeeder where TEntity : XBaseEntity { // #region Properties ... /// /// Holds Entity Name ... /// public string Entity { get; } /// /// Holds Database Name ... /// public string Database { get; } /// /// Repository Service for Data Manipulation ... /// public IXBaseRepository Repository { get; } /// /// DataServiceConfiguration ... /// public XDataServiceConfiguration DataServiceConfiguration { get; } #endregion // #region Constructor ... public XBaseDbSeeder( string entity, string database, IXBaseRepository repository, XDataServiceConfiguration dataServiceConfiguration ) { // this.Entity = entity; this.Database = database; this.Repository = repository; this.DataServiceConfiguration = dataServiceConfiguration; } #endregion public async Task Seed() { // // Validate Seed ... var isValid = DataServiceConfiguration.SeedingMode != XDbSeedingMode.None && DataServiceConfiguration .Databases .Any(db => db.Key == Database && db.Value.SeedItems .Any(si => si.Key == Entity && si.Value.HasChild())); if (!isValid) { return; } // // Extract Seeding Items ... var seedItems = DataServiceConfiguration .Databases[Database] .SeedItems[Entity] .ToList(); foreach (var item in seedItems) { // try { // var entity = item .ToJSON() .FromJSON(); // // Check Item Exists or not ... var isExist = false; TEntity exists = null; var asyncEnumerable = this.Repository.GetAllAsAsyncEnumerable(); await foreach (var e in asyncEnumerable) { // isExist = e.IsSameContent( dest: entity, propertyBlackList: new List { nameof(entity.Id), nameof(entity.Deleted) }); if (isExist) { exists = e; break; } } // // Seed Based on Seed Mode ... var seedMode = DataServiceConfiguration.SeedingMode; switch (seedMode) { // case XDbSeedingMode.AddIfNotExists: // if (!isExist) { // exists = await Repository.AddAsync( item: entity, saveChanges: true ); } break; // case XDbSeedingMode.AddOrUpdate: // exists = exists.UpdateData( updateWith: entity, propertyBlackList: new List { nameof(entity.Id), nameof(entity.Deleted) } ); // await Repository.AddOrUpdateAsync(exists); break; } } catch { } } } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseEFRepository.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Query; 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.Providers { /// /// a Base Repository Pattern Implementation Specially for EF DBs using /// EF Core Capabilities ... /// /// /// /// public abstract class XBaseEFRepository : IXBaseRepository where T : XBaseEntity where TDbContext : XDbContext { // #region Properties ... // public readonly DbSet dbSet; private readonly IXKeyGenerator keyGenerator; public readonly IXUnitOfWorks unitOfWorks; public readonly XDataServiceConfiguration configuration; private readonly IXBaseRepositoryEvents baseRepositoryEvents; #endregion // #region Constructor ... public XBaseEFRepository( IXUnitOfWorks unitOfWorks, XDataServiceConfiguration configuration, IXKeyGenerator keyGenerator = null, IXBaseRepositoryEvents baseRepositoryEvents = null ) { // this.unitOfWorks = unitOfWorks; this.keyGenerator = keyGenerator; this.configuration = configuration; this.dbSet = unitOfWorks.GetDbSet(); this.baseRepositoryEvents = baseRepositoryEvents; } #endregion // #region Actions ... // #region Add ... /// /// add a new Entity ... /// /// /// /// /// public async Task AddAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Handle Key ... item = await HandleKeyAsync( item: item, cancellationToken: cancellationToken ); // var entry = await dbSet.AddAsync( entity: item, cancellationToken: cancellationToken ); // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // 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; } /// /// add or update an Entity (add if not exists/update if exists) ... /// /// /// /// /// public async Task AddOrUpdateAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isExists = await IsExistsAsync( id: GetKey(item), cancellationToken: cancellationToken ); if (!isExists) { // return await AddAsync( item: item, saveChanges: saveChanges, cancellationToken: cancellationToken ); } else { // return await UpdateAsync( item: item, id: GetKey(item), saveChanges: saveChanges, cancellationToken: cancellationToken ); } } /// /// add a range of new Entities ... /// /// /// /// /// public async Task AddRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Preparing Ids and Keys ... await dbSet.AddRangeAsync( await Task .WhenAll( items .Select(async i => await HandleKeyAsync(i)) ), cancellationToken: cancellationToken ); // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .AddManyEvent(new XBaseEventModel>(null)); } } #endregion // #region Update ... /// /// Update an Entity values ... /// /// /// /// /// /// public async Task UpdateAsync( TKey id, T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Get Exists Entity ... var existsEntity = await GetAsync( id: id, ignoreSoftDeleteds: false, cancellationToken: cancellationToken ); // // 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(cancellationToken); // // 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; } /// /// Update a range of Entities ... /// /// /// /// /// public async Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // 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(cancellationToken); // // 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 Remove ... /// /// remove an Entity by it's Id ... /// /// /// /// /// /// public async Task RemoveAsync( TKey id, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Retrieve Item ... var item = await GetAsync( id, ignoreSoftDeleteds: false, cancellationToken: cancellationToken ); if (item.IsNullOrDefault()) { 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(cancellationToken); // // 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; } /// /// remove an Entity ... /// /// /// /// /// /// public async Task RemoveAsync( T item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var result = await RemoveAsync( id: item.Id, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); // return result; } /// /// remove a range of exists Entities ... /// /// /// /// /// /// public async Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // 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(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .RemoveManyEvent(new XBaseEventModel>(null)); } } #endregion // #region Count ... /// /// count all exists Entities ... /// /// /// /// public async Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // var result = 0; // if (ignoreSoftDeleteds) { // result = await dbSet.CountAsync( predicate: x => !x.Deleted, cancellationToken: cancellationToken ); } else { result = await dbSet.CountAsync(cancellationToken); } // return result; } /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// public async Task PagesCountAsync( int pageSize, int? totalItems = null, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // int count = totalItems.HasValue ? totalItems.Value : await CountAsync( cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); int pagesCount = count / pageSize; // if (count % pageSize > 0) { pagesCount++; } // return pagesCount; } #endregion // #region Retrieve ... /// /// retrieve whole items as queryable ... /// /// a flag for Tracking behaviour /// an Expression for Filter Items ... /// an Order Builder expression for Ordering Query ... /// an Include Builder expression for Including Navigation Properties ... /// public IQueryable AsQueryable( bool asNoTracking = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // var result = dbSet .AsQueryable(); // // Apply Predicate ... if (!predicate.IsNull()) { result = result .Where(predicate); } // // Apply Includes ... if (!includeBuilder.IsNull()) { result = includeBuilder(result); } // // Apply Ordering ... if (!orderBuilder.IsNull()) { result = orderBuilder(result); } // return result; } /// /// retrieve an Entity by it's Id ... /// /// /// /// /// /// public async Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = (await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken)) .FirstOrDefault(x => GetKey(x).ToString() == id.ToString()); // return result; } /// /// retrieve all exists Entities ... /// /// /// /// /// /// public async Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken); // return result; } /// /// retrieve all exists Entities /// as Async Enumerable ... /// /// /// /// /// public IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .AsAsyncEnumerable(); // return result; } /// /// find an Entity by providing a Conditional Expression ... /// /// /// /// /// /// public async Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = (await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken)) .FirstOrDefault(predicate.Compile()); // return result; } /// /// find a collection of Entities by proving a Conditional Expression ... /// /// /// /// /// /// /// public async Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = (await AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken)) .Where(predicate.Compile()); // return result; } /// /// retrieve Entities based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// public async Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Normalize Query ... query = query.NormalizeQuery(configuration); // var items = await GetAllAsync(); 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; } #endregion // #region Exists ... /// /// Check an Entity exists or not ... /// /// /// /// /// public async Task IsExistsAsync( TKey id, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = (await AsQueryable( asNoTracking: true, orderBuilder: null, includeBuilder: null, predicate: predicator ) .ToListAsync(cancellationToken)) .Any(predicate: x => GetKey(x).ToString() == id.ToString()); // return result; } #endregion // #region Unit Of Work ... /// /// Save all unsaved Transactions on DbContext ... /// used fo Unit Of Works Design Pattern ... /// /// /// public async Task SaveChangesAsync( CancellationToken cancellationToken = default ) { return await unitOfWorks.SaveChangesAsync(cancellationToken); } #endregion // #region Key ... /// /// Retrieve Key of Entity ... /// /// /// 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(); } /// /// Set Key of Entity ... /// /// /// 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); } /// /// Handle Checking Key ... /// /// /// /// public async Task HandleKeyAsync( T item, CancellationToken cancellationToken = default ) { // 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 ... /// /// Detach an Entity ... /// /// public void Detach(T item) { // if (item.IsNull()) { return; } // Entry(item).State = EntityState.Detached; } /// /// Detach an Enumerable of Entities ... /// /// public void Detach(IEnumerable items) { // if (items.IsNull() || !items.HasChild()) { return; } // items .ToList() .ForEach(item => { Detach(item); }); } /// /// Detach a Query Result of Entity ... /// /// public void Detach(XQueryResult query) { // if (query.IsNull() || query.Items.HasChild()) { return; } // Detach(query.Items); } #endregion #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); } #endregion // #region Private ... #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseEntityRegisterar.cs using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Providers { /// /// Base Entity Registerar ... /// public abstract class XBaseEntityRegisterar : IXEntityRegisterar { /// /// Private Entity Types Collection ... /// private readonly List entityTypes = []; /// /// Name ... /// public string Name { get; } protected XBaseEntityRegisterar(string name) { Name = name; } /// /// Add Specified Entity to Collection ... /// /// /// public void AddEntity() where TEntity : XBaseEntity { entityTypes.Add(typeof(TEntity)); } /// /// Retrieve Registered Entity Types ... /// /// public IEnumerable GetEntityTypes() { return entityTypes; } /// /// Configure Dynamic Entities ... /// /// public virtual void ConfigureEntities(ModelBuilder modelBuilder) { } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseEntityTypeConfiguration.cs using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using xModels.Base; namespace xDataService.Providers { /// /// Configure an Entity Specifications ... /// /// /// public abstract class XBaseEntityTypeConfiguration : IEntityTypeConfiguration where TEntity : XBaseEntity { public abstract void Configure(EntityTypeBuilder builder); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseInMemoryRepository.cs using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Extensions; using xDataService.Interfaces; using xDataService.Models; using xModels.Base; using xModels.Dtos; namespace xDataService.Providers { /// /// a Base Repository Pattern Implementation Specially for InMemory Stores using /// EF Core Capabilities ... /// /// /// public abstract class XBaseInMemoryRepository : IXBaseRepository where TEntity : XBaseEntity { // #region Props ... private readonly XDataServiceConfiguration configuration; private readonly IXKeyGenerator keyGenerator; private readonly IXBaseRepositoryEvents baseRepositoryEvents; private static readonly ConcurrentDictionary store = new ConcurrentDictionary(); #endregion // #region Constructor ... public XBaseInMemoryRepository( XDataServiceConfiguration configuration, IXKeyGenerator keyGenerator = null, IXBaseRepositoryEvents baseRepositoryEvents = null ) { this.keyGenerator = keyGenerator; this.configuration = configuration; this.baseRepositoryEvents = baseRepositoryEvents; } #endregion // #region Actions ... // #region Add ... /// /// add a new Entity ... /// /// /// /// /// public async Task AddAsync( TEntity item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Handle Key ... item = await HandleKeyAsync( item: item, cancellationToken: cancellationToken ); // var isSucceed = false; // // Add Item to Dictionary ... try { // store[item.Id] = item; isSucceed = true; } catch { isSucceed = false; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .AddEvent(new XBaseEventModel(item)); } // // Return Item ... return item; } /// /// add or update an Entity (add if not exists/update if exists) ... /// /// /// /// /// public async Task AddOrUpdateAsync( TEntity item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isExists = await IsExistsAsync( id: item.Id, ignoreSoftDeleteds: true, cancellationToken: cancellationToken ); // var isSucceed = false; if (isExists) { // try { // item = await UpdateAsync( item: item, id: item.Id, saveChanges: saveChanges, cancellationToken: cancellationToken ); isSucceed = true; } catch { isSucceed = false; } } else { // try { // item = await AddAsync( item: item, saveChanges: saveChanges, cancellationToken: cancellationToken ); // isSucceed = true; } catch { isSucceed = false; } } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // if (isExists) { // baseRepositoryEvents .UpdateEvent(new XBaseEventModel(item)); } else { // baseRepositoryEvents .AddEvent(new XBaseEventModel(item)); } } // return item; } /// /// add a range of new Entities ... /// /// /// /// /// public async Task AddRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return; } // foreach (var item in items) { // await AddAsync( item: item, saveChanges: saveChanges, cancellationToken: cancellationToken ); } // // Notify Event ... if ( isValid && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .AddManyEvent(new XBaseEventModel>(null)); } } #endregion // #region Update ... /// /// Update an Entity values ... /// /// /// /// /// /// public async Task UpdateAsync( TKey id, TEntity item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isExists = await IsExistsAsync( id: id, ignoreSoftDeleteds: true, cancellationToken: cancellationToken ); if (!isExists) { return null; } // var isSucceed = false; var exists = store[id]; // try { // exists = exists.UpdateData( exists, propertyBlackList: new List { nameof(exists.Id) } ); store[id] = exists; // isSucceed = true; } catch { isSucceed = false; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .UpdateEvent(new XBaseEventModel(item)); } // return exists; } /// /// Update a range of Entities ... /// /// /// /// /// public async Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var result = false; var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return result; } // foreach (var item in items) { // var updated = await UpdateAsync( item: item, id: item.Id, saveChanges: saveChanges, cancellationToken: cancellationToken ); if (!updated.IsNullOrDefault() && !result) { result = true; } } // return result; } #endregion // #region Remove ... /// /// remove an Entity by it's Id ... /// /// /// /// /// /// public async Task RemoveAsync( TKey id, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isExists = await IsExistsAsync( id: id, cancellationToken: cancellationToken ); if (!isExists) { return null; } // TEntity result = null; if (softDelete && configuration.EnableSoftDelete) { // store[id].Deleted = true; result = store[id]; } else { // result = store[id]; store.TryRemove(id, out _); } // return result; } /// /// remove an Entity ... /// /// /// /// /// /// public async Task RemoveAsync( TEntity item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var result = await RemoveAsync( id: item.Id, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); // return result; } /// /// remove a range of exists Entities ... /// /// /// /// /// /// public async Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return; } // foreach (var item in items) { // await RemoveAsync( item: item, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); } } #endregion // #region Count ... /// /// count all exists Entities ... /// /// /// /// public async Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, includeBuilder: null, predicate: predicator ) .CountAsync(cancellationToken); // return result; } /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// public async Task PagesCountAsync( int pageSize, int? totalItems = null, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // int count = totalItems.HasValue ? totalItems.Value : await CountAsync( cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); int pagesCount = count / pageSize; // if (count % pageSize > 0) { pagesCount++; } // return pagesCount; } #endregion // #region Exists ... /// /// Check an Entity exists or not ... /// /// /// /// /// public async Task IsExistsAsync( TKey id, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, includeBuilder: null, predicate: predicator ) .AnyAsync( cancellationToken: cancellationToken, predicate: x => GetKey(x).ToString() == id.ToString()); // return result; } #endregion // #region Retrieve ... /// /// retrieve whole items as queryable ... /// /// a flag for Tracking behaviour /// an Expression for Filter Items ... /// an Order Builder expression for Ordering Query ... /// an Include Builder expression for Including Navigation Properties ... /// public IQueryable AsQueryable( bool asNoTracking = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // var result = store.Values.AsQueryable(); // // Predicate ... if (!predicate.IsNull()) { result = result.Where(predicate); } // // Apply Orders ... if (!orderBuilder.IsNull()) { result = orderBuilder(result); } // // Apply Includes ... if (!includeBuilder.IsNull()) { result = includeBuilder(result); } // if (asNoTracking) { result = result.AsNoTracking(); } // return result; } /// /// retrieve an Entity by it's Id ... /// /// /// /// /// /// public async Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .Where(x => GetKey(x).ToString() == id.ToString()) .FirstOrDefaultAsync(cancellationToken); // return result; } /// /// retrieve all exists Entities ... /// /// /// /// /// /// public async Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken); // return result; } /// /// retrieve all exists Entities /// as Async Enumerable ... /// /// /// /// /// public IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .AsAsyncEnumerable(); // return result; } /// /// find an Entity by providing a Conditional Expression ... /// /// /// /// /// /// public async Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .Where(predicate) .FirstOrDefaultAsync(cancellationToken); // return result; } /// /// find a collection of Entities by proving a Conditional Expression ... /// /// /// /// /// /// /// public async Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .Where(predicate) .ToListAsync(cancellationToken); // return result; } /// /// retrieve Entities based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// public async Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Normalize Query ... query = query.NormalizeQuery(configuration); // var items = await GetAllAsync(); 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; } #endregion // #region Unit Of Work ... /// /// Save all unsaved Transactions on DbContext ... /// used fo Unit Of Works Design Pattern ... /// /// /// public async Task SaveChangesAsync( CancellationToken cancellationToken = default ) { // return await Task.Run( () => 0, cancellationToken ); } #endregion // #region Key ... /// /// Retrieve Key of Entity ... /// /// /// public TKey GetKey(TEntity 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(); } /// /// Set Key of Entity ... /// /// /// public void SetKey( ref TEntity 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); } /// /// Handle Checking Key ... /// /// /// /// public async Task HandleKeyAsync( TEntity item, CancellationToken cancellationToken = default ) { // 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 ... /// /// Detach an Entity ... /// /// public void Detach(TEntity item) { } /// /// Detach an Enumerable of Entities ... /// /// public void Detach(IEnumerable items) { } /// /// Detach a Query Result of Entity ... /// /// public void Detach(XQueryResult query) { } #endregion #endregion // #region Others ... public void Dispose() { } #endregion // #region Private ... #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseMongoRepository.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using MongoDB.Driver; using MongoDB.Driver.Linq; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Extensions; using xDataService.Interfaces; using xDataService.Models; using xModels.Base; using xModels.Dtos; namespace xDataService.Providers { /// /// a Base Repository Pattern Implementation Specially for Mongo DBs using /// EF Core Capabilities ... /// /// /// public abstract class XBaseMongoRepository : IXBaseRepository where T : XBaseEntity { // #region Properties ... private readonly string collectionName; public List> bulkCollection; public readonly IMongoCollection collection; private readonly IXKeyGenerator keyGenerator; public readonly XDataBaseConfiguration dbConfiguration; public readonly XDataServiceConfiguration configuration; private readonly IXBaseRepositoryEvents baseRepositoryEvents; #endregion // #region Constructor ... protected XBaseMongoRepository( XDataBaseConfiguration dbConfiguration, XDataServiceConfiguration configuration, string collectionName = null, IXKeyGenerator keyGenerator = null, IXBaseRepositoryEvents baseRepositoryEvents = null ) { // this.keyGenerator = keyGenerator; this.configuration = configuration; this.collectionName = collectionName .IsNullOrEmpty() ? typeof(T).Name : collectionName; this.dbConfiguration = dbConfiguration; this.baseRepositoryEvents = baseRepositoryEvents; // var client = new MongoClient(dbConfiguration.GetMongoDbURI()); var database = client.GetDatabase(dbConfiguration.GetMongoDbDatabase()); // bulkCollection = new List>(); collection = database.GetCollection( this.collectionName ); } #endregion // #region Actions ... // #region Add ... /// /// add a new Entity ... /// /// /// /// /// public async Task AddAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Handle Key ... item = await HandleKeyAsync( item: item, cancellationToken: cancellationToken ); // // Add Action model to Bulk Collection ... bulkCollection.Add(new InsertOneModel(item)); // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .AddEvent(new XBaseEventModel(item)); } // // Return result base on action Succeed ... return isSucceed ? item : null; } /// /// add or update an Entity (add if not exists/update if exists) ... /// /// /// /// /// public async Task AddOrUpdateAsync( T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isExists = await IsExistsAsync( id: GetKey(item), ignoreSoftDeleteds: true, cancellationToken: cancellationToken ); if (!isExists) { // // Handle Key ... item = await HandleKeyAsync( item: item, cancellationToken: cancellationToken ); // // Add Action model to Bulk Collection ... bulkCollection .Add(new InsertOneModel(item)); } else { // // Filter ... var filter = Builders.Filter.Eq(i => i.Id, item.Id); // // Add Action model to Bulk Collection ... bulkCollection .Add(new ReplaceOneModel(filter, item) { IsUpsert = true }); } // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // if (isExists) { // baseRepositoryEvents .UpdateEvent(new XBaseEventModel(item)); } else { // baseRepositoryEvents .AddEvent(new XBaseEventModel(item)); } } // // Return result base on action Succeed ... return isSucceed ? item : null; } /// /// add a range of new Entities ... /// /// /// /// /// public async Task AddRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return; } // foreach (var item in items) { // await AddAsync( item: item, saveChanges: saveChanges, cancellationToken: cancellationToken ); } // // Notify Event ... if ( isValid && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .AddManyEvent(new XBaseEventModel>(null)); } } #endregion // #region Update ... /// /// Update an Entity values ... /// /// /// /// /// /// public async Task UpdateAsync( TKey id, T item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Filter ... var filter = Builders.Filter.Eq(i => i.Id, id); // // Add Action model to Bulk Collection ... bulkCollection.Add(new ReplaceOneModel(filter, item) { IsUpsert = false }); // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .UpdateEvent(new XBaseEventModel(item)); } // // Return result base on action Succeed ... return isSucceed ? item : null; } /// /// Update a range of Entities ... /// /// /// /// /// public async Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var result = false; var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return result; } // foreach (var item in items) { // var updated = await UpdateAsync( item: item, id: item.Id, saveChanges: saveChanges, cancellationToken: cancellationToken ); if (!updated.IsNullOrDefault() && !result) { result = true; } } // return result; } #endregion // #region Remove ... /// /// remove an Entity by it's Id ... /// /// /// /// /// /// public async Task RemoveAsync( TKey id, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Retrieve Item ... var item = await GetAsync( id: id, ignoreSoftDeleteds: true, cancellationToken: cancellationToken ); if (item.IsNull()) { return null; } // // Filter ... var filter = Builders.Filter.Eq(i => i.Id, id); // // Check SoftDelete ... if (softDelete && configuration.EnableSoftDelete) { // // Set Soft Delete ... item.Deleted = true; // // Update ... // Add Action model to Bulk Collection ... bulkCollection.Add(new ReplaceOneModel(filter, item) { IsUpsert = true }); } else { // // Delete ... // Add Action model to Bulk Collection ... bulkCollection.Add(new DeleteOneModel(filter)); } // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .RemoveEvent(new XBaseEventModel(item)); } // // Return result base on action Succeed ... return isSucceed ? item : null; } /// /// remove an Entity ... /// /// /// /// /// /// public async Task RemoveAsync( T item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // var result = await RemoveAsync( id: item.Id, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); // return result; } /// /// remove a range of exists Entities ... /// /// /// /// /// /// public async Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // loop through items ... foreach (var item in items) { // // Filter ... var filter = Builders.Filter.Eq(i => i.Id, item.Id); // // Check Soft Delete ... if (softDelete && configuration.EnableSoftDelete) { // // Set Soft Delete ... item.Deleted = true; // // Update ... // Add Action model to Bulk Collection ... bulkCollection.Add(new ReplaceOneModel(filter, item) { IsUpsert = true }); } else { // // Delete ... // Add Action model to Bulk Collection ... bulkCollection.Add(new DeleteOneModel(filter)); } } // // Check action is Succeeded or not ... var isSucceed = false; if (saveChanges) { // // Get Modified Count ... var qResult = await SaveChangesAsync(cancellationToken); // // set isSucceed Value based on Changes ... isSucceed = qResult > 0; } // // Notify Event ... if ( isSucceed && !baseRepositoryEvents.IsNull() ) { // baseRepositoryEvents .RemoveManyEvent(new XBaseEventModel>(null)); } } #endregion // #region Count ... /// /// count all exists Entities ... /// /// /// /// public async Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, includeBuilder: null, predicate: predicator ) .CountAsync(cancellationToken); // return result; } /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// public async Task PagesCountAsync( int pageSize, int? totalItems = null, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // int count = totalItems.HasValue ? totalItems.Value : await CountAsync( cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); int pagesCount = count / pageSize; // if (count % pageSize > 0) { pagesCount++; } // return pagesCount; } #endregion // #region Retrieve ... /// /// retrieve whole items as queryable ... /// /// a flag for Tracking behaviour /// an Expression for Filter Items ... /// an Order Builder expression for Ordering Query ... /// an Include Builder expression for Including Navigation Properties ... /// public IQueryable AsQueryable( bool asNoTracking = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // var result = collection .AsQueryable(); // // Apply Predicate ... if (!predicate.IsNull()) { result = result .Where(predicate); } // // Apply Includes ... if (!includeBuilder.IsNull()) { // // Since Mongo Queryable doesnt Support Includes ... // we ignore this ... result = (IMongoQueryable)includeBuilder(result); } // // Apply Ordering ... if (!orderBuilder.IsNull()) { result = (IMongoQueryable)orderBuilder(result); } // return result; } /// /// retrieve an Entity by it's Id ... /// /// /// /// /// /// public async Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .Where(x => GetKey(x).ToString() == id.ToString()) .FirstOrDefaultAsync(cancellationToken); // return result; } /// /// retrieve all exists Entities ... /// /// /// /// /// /// public async Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .ToListAsync(cancellationToken); // return result; } /// /// retrieve all exists Entities /// as Async Enumerable ... /// /// /// /// /// public IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .AsAsyncEnumerable(); // return result; } /// /// find an Entity by providing a Conditional Expression ... /// /// /// /// /// /// public async Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, predicate: predicator, includeBuilder: includeBuilder ) .Where(predicate) .FirstOrDefaultAsync(cancellationToken); // return result; } /// /// find a collection of Entities by proving a Conditional Expression ... /// /// /// /// /// /// /// public async Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, predicate: predicator, orderBuilder: orderBuilder, includeBuilder: includeBuilder ) .Where(predicate) .ToListAsync(cancellationToken); // return result; } /// /// retrieve Entities based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// public async Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // // Normalize Query ... query = query.NormalizeQuery(configuration); // var items = await GetAllAsync(); 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; } #endregion // #region Exists ... /// /// Check an Entity exists or not ... /// /// /// /// /// public async Task IsExistsAsync( TKey id, bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // // Prepare Ignore Soft Deleted Predicator ... Expression> predicator = null; if (ignoreSoftDeleteds) { predicator = x => !x.Deleted; } var result = await AsQueryable( asNoTracking: true, orderBuilder: null, includeBuilder: null, predicate: predicator ) .AnyAsync( cancellationToken: cancellationToken, predicate: x => GetKey(x).ToString() == id.ToString()); // return result; } #endregion // #region Unit Of Work ... /// /// Save all unsaved Transactions on DbContext ... /// used fo Unit Of Works Design Pattern ... /// /// /// public async Task SaveChangesAsync( CancellationToken cancellationToken = default ) { // try { // // Write all Bulk Models which stored inside bulkCollection ... var result = await collection .BulkWriteAsync( options: null, requests: bulkCollection, cancellationToken: cancellationToken ); // // Clear Bulk Collection ... bulkCollection.Clear(); // // Return number of Modified Documents ... var resultCount = (int)result.ModifiedCount + (int)result.InsertedCount + (int)result.DeletedCount; // return resultCount; } catch (Exception ex) { // // Log Thrown Exception ... Console.WriteLine($"XMongo Repository Exception: {ex.Message} ..."); // // Return less than zero value ... return -1; } } #endregion // #region Key ... /// /// Retrieve Key of Entity ... /// /// /// 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(); } /// /// Set Key of Entity ... /// /// /// 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); } /// /// Handle Checking Key ... /// /// /// /// public async Task HandleKeyAsync( T item, CancellationToken cancellationToken = default ) { // 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 ... /// /// Detach an Entity ... /// /// public void Detach(T item) { } /// /// Detach an Enumerable of Entities ... /// /// public void Detach(IEnumerable items) { } /// /// Detach a Query Result of Entity ... /// /// public void Detach(XQueryResult query) { } #endregion #endregion // #region Others ... public void Dispose() { } public string GetPropValues(T item) { // var props = item.GetType().GetProperties(); var vals = props.Select(p => p.GetValue(p.Name)); // return vals.ToJSON(); } #endregion // #region Private ... #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseRepositoryEvents.cs using System; using System.Collections.Generic; using System.Reactive.Linq; using System.Reactive.Subjects; using xDataService.Interfaces; using xDataService.Models; namespace xDataService.Providers { /// /// Some Events can be Raised on Some Actions Happens on Repositories ... /// this is the Base Events Class ... /// /// public abstract class XBaseRepositoryEvents : IXBaseRepositoryEvents { // private readonly ISubject> onAddSubject; private readonly ISubject> onUpdateSubject; private readonly ISubject> onRemoveSubject; // private readonly ISubject>> onAddManySubject; private readonly ISubject>> onUpdateManySubject; private readonly ISubject>> onRemoveManySubject; // protected XBaseRepositoryEvents () { // onAddSubject = new ReplaySubject> (1); onUpdateSubject = new ReplaySubject> (1); onRemoveSubject = new ReplaySubject> (1); // onAddManySubject = new ReplaySubject>> (1); onUpdateManySubject = new ReplaySubject>> (1); onRemoveManySubject = new ReplaySubject>> (1); } // public void AddEvent (XBaseEventModel model) => onAddSubject.OnNext (model); public void UpdateEvent (XBaseEventModel model) => onUpdateSubject.OnNext (model); public void RemoveEvent (XBaseEventModel model) => onRemoveSubject.OnNext (model); // public void AddManyEvent (XBaseEventModel> model) => onAddManySubject.OnNext (model); public void UpdateManyEvent (XBaseEventModel> model) => onUpdateManySubject.OnNext (model); public void RemoveManyEvent (XBaseEventModel> model) => onRemoveManySubject.OnNext (model); // public IObservable> OnAddObservable => onAddSubject.AsObservable (); public IObservable> OnUpdateObservable => onUpdateSubject.AsObservable (); public IObservable> OnRemoveObservable => onRemoveSubject.AsObservable (); // public IObservable>> OnAddManyObservable => onAddManySubject.AsObservable (); public IObservable>> OnUpdateManyObservable => onUpdateManySubject.AsObservable (); public IObservable>> OnRemoveManyObservable => onRemoveManySubject.AsObservable (); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XBaseRepositoryService.cs using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.CompilerServices; 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 { /// /// 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: /// > /// > /// > /// /// /// /// public abstract class XBaseRepositoryService : IXBaseRepositoryService where TEntity : XBaseEntity where TDto : XBaseEntityDto { // #region Properties ... /// /// Mapper Instance ... /// public IMapper Mapper { get; } /// /// Repository Implementation for Data Manipulations ... /// public IXBaseRepository Repository { get; } /// /// 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 ... /// public MapperConfiguration MapperConfiguration { get; } #endregion // #region Constructor ... public XBaseRepositoryService( IXBaseRepository repository, IEnumerable mapperProfiles = null ) { // Repository = repository; // // Preparing Mapping Configurations ... MapperConfiguration = new MapperConfiguration(cfg => { // // Add Default Profiles ... // // Entity To Dto ... cfg.CreateMap() .ForMember(dest => dest.Deleted, opt => opt.Ignore()); cfg.CreateMap, XQueryResult>(); // // Dto to Entity ... cfg.CreateMap() .ForMember(dest => dest.Deleted, opt => opt.Ignore()); cfg.CreateMap, XQueryResult>(); // // 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 ... /// /// add a new Dto ... /// /// /// /// /// public async Task 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(item); // entity = await Repository.AddAsync( item: entity, saveChanges: saveChanges, cancellationToken: cancellationToken ); // result = Mapper.Map(entity); } catch { } // return result; } /// /// add or update a Dto (add if not exists/update if exists) ... /// /// /// /// /// public async Task 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(item); // entity = await Repository.AddOrUpdateAsync( item: entity, saveChanges: saveChanges, cancellationToken: cancellationToken ); // result = Mapper.Map(entity); } catch { } // return result; } /// /// add a range of new Dtos ... /// /// /// /// /// public async Task AddRangeAsync( IEnumerable 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>(items); // await Repository.AddRangeAsync( items: entities, saveChanges: saveChanges, cancellationToken: cancellationToken ); } catch { } } #endregion // #region Update ... /// /// Update an Dto values ... /// /// /// /// /// /// public async Task UpdateAsync( TKey id, TDto item, bool saveChanges = true, CancellationToken cancellationToken = default ) { // TDto result = null; // try { // var entity = Mapper.Map(item); // entity = await Repository.UpdateAsync( id: item.Id, item: entity, saveChanges: saveChanges, cancellationToken: cancellationToken ); // result = Mapper.Map(entity); } catch { } // return result; } /// /// Update a range of Dtos ... /// /// /// /// /// public async Task UpdateRangeAsync( IEnumerable items, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Validate ... var result = !items.IsNull() && items.HasChild(); if (!result) { return result; } // try { // var entitis = Mapper.Map>(items); // result = await Repository.UpdateRangeAsync( items: entitis, saveChanges: saveChanges, cancellationToken: cancellationToken ); } catch { result = false; } // return result; } #endregion // #region Remove ... /// /// remove an Dto by it's Id ... /// /// /// /// /// /// public async Task 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(entity); } catch { } // return result; } /// /// remove an Dto ... /// /// /// /// /// /// public async Task RemoveAsync( TDto item, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // TDto result = null; // try { // var entity = Mapper.Map(item); // entity = await Repository.RemoveAsync( item: entity, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); // result = Mapper.Map(entity); } catch { } // return result; } /// /// remove a range of exists Dtos ... /// /// /// /// /// /// public async Task RemoveRangeAsync( IEnumerable items, bool softDelete = true, bool saveChanges = true, CancellationToken cancellationToken = default ) { // // Validate ... var isValid = !items.IsNull() && items.HasChild(); if (!isValid) { return; } // var entities = Mapper.Map>(items); // try { // await Repository.RemoveRangeAsync( items: entities, softDelete: softDelete, saveChanges: saveChanges, cancellationToken: cancellationToken ); } catch { } } #endregion // #region Count ... /// /// count all exists Dtos ... /// /// /// /// public async Task CountAsync( bool ignoreSoftDeleteds = true, CancellationToken cancellationToken = default ) { // var result = await Repository.CountAsync( cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // return result; } /// /// count all exists Entities Pages by providing page size ... /// /// /// /// /// /// public async Task 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 ... /// /// Check a Dto exists or not ... /// /// /// /// /// public async Task 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 ... /// /// retrieve an Dto by it's Id ... /// /// /// /// /// /// public async Task GetAsync( TKey id, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> 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(entity); } catch { } // return result; } /// /// retrieve all exists Dtos ... /// /// /// /// /// /// public async Task> GetAllAsync( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // IEnumerable result = Enumerable.Empty(); // try { // var entities = await Repository.GetAllAsync( orderBuilder: orderBuilder, includeBuilder: includeBuilder, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // result = Mapper.Map>(entities); } catch { } // return result; } /// /// retrieve all exists Dtos /// as Async Enumerable ... /// /// /// /// /// /// public async IAsyncEnumerable GetAllAsAsyncEnumerable( bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, [EnumeratorCancellation] CancellationToken cancellationToken = default ) { // var entityEnumerable = Repository.GetAllAsAsyncEnumerable( orderBuilder: orderBuilder, includeBuilder: includeBuilder, ignoreSoftDeleteds: ignoreSoftDeleteds ); await foreach (var entity in entityEnumerable) { // if (cancellationToken.IsCancellationRequested) { yield break; } // var dto = Mapper.Map(entity); yield return dto; } } /// /// find an Dto by providing a Conditional Expression ... /// /// /// /// /// /// public async Task FindOneAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IIncludableQueryable> 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(entity); } catch { } // return result; } /// /// find a collection of Dtos by proving a Conditional Expression ... /// /// /// /// /// /// /// public async Task> FindManyAsync( Expression> predicate, bool ignoreSoftDeleteds = true, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // IEnumerable result = Enumerable.Empty(); // try { // var entities = await Repository.FindManyAsync( predicate: predicate, orderBuilder: orderBuilder, includeBuilder: includeBuilder, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // result = Mapper.Map>(entities); } catch { } // return result; } /// /// retrieve Dtos based on XQuery Pagination structure ... /// /// /// /// /// /// /// /// public async Task> QueryAsync( XQuery query, bool ignoreSoftDeleteds = true, Expression> predicate = null, Func, IOrderedQueryable> orderBuilder = null, Func, IIncludableQueryable> includeBuilder = null, CancellationToken cancellationToken = default ) { // XQueryResult result = null; // try { // var entityResult = await Repository.QueryAsync( query: query, predicate: predicate, orderBuilder: orderBuilder, includeBuilder: includeBuilder, cancellationToken: cancellationToken, ignoreSoftDeleteds: ignoreSoftDeleteds ); // result = Mapper.Map>(entityResult); } catch { } // return result; } #endregion public virtual void Dispose() { } #endregion } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XEntityRegisterarHandlerService.cs using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore; using xCommons.Extensions; using xDataService.Interfaces; namespace xDataService.Providers { public class XEntityRegisterarHandlerService { /// /// a Collection for Extract Registerars Services ... /// private readonly List registerars = []; /// /// a Collection for Holding all Entity Types ... /// public IReadOnlyList AllEntityTypes { get; private set; } /// /// Retrieve Specified Registerars Entity Types ... /// /// /// public IReadOnlyList GetEntityTypes(string[] names = null) { // var items = new List(); // if (!names.IsNull() && names.HasChild()) { // items = [.. registerars .Where(r => names.Contains(r.Name)) .SelectMany(r => r.GetEntityTypes())]; } // return items.AsReadOnly(); } /// /// Load all Dynamically Registered Entities ... /// public void HandleRegisteredEntities() { // var entityTypes = new List(); // path = Path.Combine (Directory.GetCurrentDirectory ()); var path = Path.Combine (AppContext.BaseDirectory); var files = Directory.GetFiles(path, "*.dll"); foreach (var dll in files) { // // Retrieve DLL Assembly ... var assembly = Assembly.LoadFrom(dll); // // Extract Registerar Types ... var registerarTypes = assembly .GetExportedTypes() .Where(t => !t.IsAbstract && typeof(IXEntityRegisterar).IsAssignableFrom(t)); foreach (var registerarType in registerarTypes) { // // Create Instance of Registerar Type ... var registerar = (IXEntityRegisterar)Activator.CreateInstance(registerarType); if (!registerar.IsNull()) { // // Add Registerar Instance to Collection ... registerars.Add(registerar); // // Add Registerar Provided Entities to Collection ... entityTypes.AddRange(registerar.GetEntityTypes()); } } // // Converts to Readonly List ... AllEntityTypes = entityTypes.AsReadOnly(); } } /// /// Configure all Dynamically Registered Entities ... /// /// /// public void HandleApplyRegisteredEntitiesConfigurations( ModelBuilder modelBuilder, string[] names = null ) { // var selectedRegisterars = !names.IsNull() && names.HasChild() ? registerars .Where(r => names.Contains(r.Name)) : registerars; // // Loop Through Extracted Registerars ... foreach(var registerar in selectedRegisterars) { // // Configure Specified Registerars Entities ... registerar.ConfigureEntities(modelBuilder); } } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XGuidKeyGenerator.cs using System; using System.Threading; using System.Threading.Tasks; using xCommons.Extensions; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Providers { /// /// Default Guid Key Generator ... /// /// public class XGuidKeyGenerator : XKeyGenerator, IXKeyGenerator where TEntity : XBaseEntity { private readonly IXSequentialGuid sequentialGuid; public XGuidKeyGenerator( IXSequentialGuid sequentialGuid = null ) { this.sequentialGuid = sequentialGuid; } public override async Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ) { // return await Task.Run(() => { // // Check if provided SequentialGuid ... if (sequentialGuid.IsNull()) { return Guid.NewGuid(); } else { return sequentialGuid.Next(); } }, cancellationToken: cancellationToken); } public override bool IsEmpty(Guid id) { // var result = id.IsNull() || id.IsDefaultGuid(); // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XIntKeyGenerator.cs 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 { /// /// Default Int Key Generator ... /// /// public class XIntKeyGenerator : XKeyGenerator, IXKeyGenerator where TEntity : XBaseEntity { public override async Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ) { // var items = (await repository.GetAllAsync()) .OrderByDescending(nameof(XBaseEntity.Id)); var last = items .FirstOrDefault(); // var result = last.IsNull() ? 1 : last.Id + 1; // return result; } public override bool IsEmpty(int id) { // var result = id <= 0; // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XKeyGenerator.cs using System.Threading; using System.Threading.Tasks; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Providers { public abstract class XKeyGenerator : IXKeyGenerator where TEntity : XBaseEntity { public abstract Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ); public abstract bool IsEmpty(TKey id); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XLongKeyGenerator.cs 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 { /// /// Default Long Key Generator ... /// /// public class XLongKeyGenerator : XKeyGenerator, IXKeyGenerator where TEntity : XBaseEntity { public override async Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ) { // var items = (await repository.GetAllAsync()) .OrderByDescending(nameof(XBaseEntity.Id)); var last = items .FirstOrDefault(); // var result = last.IsNull() ? 1 : last.Id + 1; // return result; } public override bool IsEmpty(long id) { // var result = id <= 0; // return result; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XSequentialGuid.cs using System; using xDataService.Interfaces; namespace xDataService.Helpers { /// /// this service provide Sequential GUID mechanism for Entity Ids ... /// public class XSequentialGuid : IXSequentialGuid { private static int[] sqlOrderMap = null; private static int[] SQLORDERMAP { get { if (sqlOrderMap == null) { sqlOrderMap = new int[16] { 3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10 }; // 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause] // 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause] } return sqlOrderMap; } } private Guid currentGuid; public XSequentialGuid() { currentGuid = Guid.NewGuid(); } public Guid GetCurrentGuid() { return currentGuid; } public Guid Next() { byte[] bytes = currentGuid.ToByteArray(); for (int mapIndex = 0; mapIndex < 16; mapIndex++) { int bytesIndex = SQLORDERMAP[mapIndex]; bytes[bytesIndex]++; if (bytes[bytesIndex] != 0) { break; // No need to increment more significant bytes } } currentGuid = new Guid(bytes); return currentGuid; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xDataService\Providers\XStringKeyGenerator.cs using System; using System.Threading; using System.Threading.Tasks; using xCommons.Extensions; using xDataService.Interfaces; using xModels.Base; namespace xDataService.Providers { /// /// Default Guid Key Generator ... /// /// public class XStringKeyGenerator : XKeyGenerator, IXKeyGenerator where TEntity : XBaseEntity { private readonly IXSequentialGuid sequentialGuid; public XStringKeyGenerator(IXSequentialGuid sequentialGuid = null) { this.sequentialGuid = sequentialGuid; } public override async Task GenerateKey( IXBaseRepository repository, CancellationToken cancellationToken = default ) { // await Task.CompletedTask; // if (sequentialGuid.IsNull()) { return Guid.NewGuid().ToString(); } else { return sequentialGuid.Next().ToString(); } } public override bool IsEmpty(string id) { return id.IsNullOrEmpty(); } } }