12 Commits

Author SHA1 Message Date
Developer 02
e0737299cf Bump version to 1.1.1 in project file
Updated DigitalData.Core.Exceptions.csproj to set <Version>, <AssemblyVersion>, and <FileVersion> to 1.1.1, replacing the previous 1.1.0 values. No other changes were made.
2026-01-21 22:06:35 +01:00
Developer 02
2db99edcda Add constructor to BadRequestException for inner exceptions
Added a new constructor to BadRequestException that accepts both a message and an inner exception, enabling improved exception chaining and more detailed error reporting.
2026-01-21 22:05:16 +01:00
65186b4f47 chore(Infrastructure): bump to 2.6.1 2026-01-12 10:23:26 +01:00
eb3a5b8991 Apply AsNoTracking to raw/interpolated queries in DbRepository
QueryRaw and QueryInterpolated now always return results with AsNoTracking applied, ensuring entities are not tracked by EF Core. Both methods are now virtual, allowing for easier customization in derived classes. This change improves performance and prevents unintended side effects from entity tracking.
2026-01-12 10:02:56 +01:00
908d85c648 refactor(Core.Abstraction.Application): bump to 1.6.0 2025-12-19 10:23:45 +01:00
d0f055e066 Bump version to 2.6.0 in csproj metadata
Updated <Version>, <AssemblyVersion>, and <FileVersion> fields in DigitalData.Core.Infrastructure.csproj from 2.5.2 to 2.6.0 to reflect the new release.
2025-12-19 10:13:25 +01:00
7f9e6155fe Add repository registration to DI setup
Added RegsRepository.InvokeAll(services) to the dependency injection configuration, ensuring repository types are registered alongside entities and DbSet factories.
2025-12-19 10:11:14 +01:00
1e3cba6fdf Refactor DependencyInjection and RepositoryConfiguration classes
Restructure code for improved readability and maintainability. Move RepositoryConfiguration as a nested public class inside DependencyInjection, group related service registration logic, and clarify method organization. No functional changes.
2025-12-19 10:09:04 +01:00
daa36d767d Refactor repository registration to be context-based
Changed RegisterDefaultRepository to register repositories by DbContext only, removing the entity-specific generic parameter. Added a private InvokeAll<T> helper to process queued service registrations. This streamlines repository registration and improves code maintainability.
2025-12-19 10:03:25 +01:00
3021fd36f6 Implement IRepository in DbRepository<TDbContext>
DbRepository<TDbContext> now implements the IRepository interface, ensuring it conforms to the expected repository contract and interface requirements. This change improves consistency and enforces interface adherence across repository implementations.
2025-12-19 10:01:20 +01:00
2c704c1231 Add raw SQL support to repository interfaces and DI
Extended IRepository interfaces and DbRepository implementation to support raw and interpolated SQL query execution (sync/async) and querying. Updated DependencyInjection to allow registration of default repository implementations. Added Microsoft.EntityFrameworkCore.Abstractions as a dependency. Performed minor refactoring and cleanup.
2025-12-19 09:54:56 +01:00
2bf2bb2276 Refactor namespace and add System.Linq import
Removed conditional compilation around the namespace in DbRepository.cs, making it always use standard braces. Added System.Linq using directive to support LINQ operations.
2025-12-19 09:51:22 +01:00
6 changed files with 121 additions and 118 deletions

View File

@@ -12,9 +12,9 @@
<PackageIcon>core_icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackageTags>digital data core application clean architecture abstraction</PackageTags>
<Version>1.5.0</Version>
<AssemblyVersion>1.5.0</AssemblyVersion>
<FileVersion>1.5.0</FileVersion>
<Version>1.6.0</Version>
<AssemblyVersion>1.6.0</AssemblyVersion>
<FileVersion>1.6.0</FileVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -19,4 +19,13 @@ public class BadRequestException : Exception
public BadRequestException(string? message) : base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BadRequestException"/> class with a specified error message and inner exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that caused the current exception.</param>
public BadRequestException(string? message, Exception? innerException) : base(message, innerException)
{
}
}

View File

@@ -17,9 +17,9 @@
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackAsTool>False</PackAsTool>
<PackageIcon>core_icon.png</PackageIcon>
<Version>1.1.0</Version>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0</FileVersion>
<Version>1.1.1</Version>
<AssemblyVersion>1.1.1</AssemblyVersion>
<FileVersion>1.1.1</FileVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -100,9 +100,9 @@ namespace DigitalData.Core.Infrastructure
#region Read
public virtual IQueryable<TEntity> Query => Entities.AsNoTracking();
public IQueryable<TEntity> QueryRaw([NotParameterized] string sql, params object[] parameters) => Entities.FromSqlRaw(sql, parameters);
public virtual IQueryable<TEntity> QueryRaw([NotParameterized] string sql, params object[] parameters) => Entities.FromSqlRaw(sql, parameters).AsNoTracking();
public IQueryable<TEntity> QueryInterpolated([NotParameterized] FormattableString sql) => Entities.FromSqlInterpolated(sql);
public virtual IQueryable<TEntity> QueryInterpolated([NotParameterized] FormattableString sql) => Entities.FromSqlInterpolated(sql).AsNoTracking();
public virtual IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> expression) => Entities.AsNoTracking().Where(expression);

View File

@@ -11,143 +11,137 @@ using System.Linq;
#endif
namespace DigitalData.Core.Infrastructure
#if NET
;
#elif NETFRAMEWORK
{
#endif
public static class DependencyInjection
{
public static IServiceCollection AddDbRepository(this IServiceCollection services, Action<RepositoryConfiguration> options)
public static class DependencyInjection
{
// register services from configuration
var cfg = new RepositoryConfiguration();
options.Invoke(cfg);
cfg.RegisterAllServices(services);
return services;
}
public class RepositoryConfiguration
{
// 1. register from assembly
private readonly Queue<Action<IServiceCollection>> RegsFromAssembly = new Queue<Action<IServiceCollection>>();
// 2. register entities (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsEntity = new Queue<Action<IServiceCollection>>();
// 3. register db set factories (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsDbSetFactory = new Queue<Action<IServiceCollection>>();
// 4. register repository
private readonly Queue<Action<IServiceCollection>> RegsRepository = new Queue<Action<IServiceCollection>>();
internal void RegisterAllServices(IServiceCollection services)
public static IServiceCollection AddDbRepository(this IServiceCollection services, Action<RepositoryConfiguration> options)
{
// 1. register from assembly
RegsFromAssembly.InvokeAll(services);
// register services from configuration
var cfg = new RepositoryConfiguration();
options.Invoke(cfg);
cfg.RegisterAllServices(services);
// 2. register entities (can overwrite)
RegsEntity.InvokeAll(services);
// 3. register db set factories (can overwrite)
RegsDbSetFactory.InvokeAll(services);
return services;
}
internal RepositoryConfiguration() { }
public void RegisterFromAssembly<TDbContext>(Assembly assembly) where TDbContext : DbContext
public class RepositoryConfiguration
{
void reg(IServiceCollection services)
// 1. register from assembly
private readonly Queue<Action<IServiceCollection>> RegsFromAssembly = new Queue<Action<IServiceCollection>>();
// 2. register entities (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsEntity = new Queue<Action<IServiceCollection>>();
// 3. register db set factories (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsDbSetFactory = new Queue<Action<IServiceCollection>>();
// 4. register repository
private readonly Queue<Action<IServiceCollection>> RegsRepository = new Queue<Action<IServiceCollection>>();
internal void RegisterAllServices(IServiceCollection services)
{
// scan all types in the Assembly
var entityTypes = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.GetCustomAttribute<TableAttribute>() != null);
// 1. register from assembly
RegsFromAssembly.InvokeAll(services);
foreach (var entityType in entityTypes)
// 2. register entities (can overwrite)
RegsEntity.InvokeAll(services);
// 3. register db set factories (can overwrite)
RegsDbSetFactory.InvokeAll(services);
// 4. register repository
RegsRepository.InvokeAll(services);
}
internal RepositoryConfiguration() { }
public void RegisterFromAssembly<TDbContext>(Assembly assembly) where TDbContext : DbContext
{
void reg(IServiceCollection services)
{
#region Repository
/// register repository
// create generic DbRepository<DbContext, TEntity> type
var repositoryType = typeof(DbRepository<,>).MakeGenericType(typeof(TDbContext), entityType);
var interfaceType = typeof(IRepository<>).MakeGenericType(entityType);
// scan all types in the Assembly
var entityTypes = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.GetCustomAttribute<TableAttribute>() != null);
// add into DI container as Scoped
services.AddScoped(interfaceType, repositoryType);
#endregion Repository
foreach (var entityType in entityTypes)
{
#region Repository
/// register repository
// create generic DbRepository<DbContext, TEntity> type
var repositoryType = typeof(DbRepository<,>).MakeGenericType(typeof(TDbContext), entityType);
var interfaceType = typeof(IRepository<>).MakeGenericType(entityType);
#region DbSetFactory
/// register DbSetFactory
var addDbSetFactoryMethod = typeof(DependencyInjection)
.GetMethod(nameof(AddDbSetFactory),
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
// add into DI container as Scoped
services.AddScoped(interfaceType, repositoryType);
#endregion Repository
var genericMethod = addDbSetFactoryMethod
#region DbSetFactory
/// register DbSetFactory
var addDbSetFactoryMethod = typeof(DependencyInjection)
.GetMethod(nameof(AddDbSetFactory),
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var genericMethod = addDbSetFactoryMethod
#if NET
!
#endif
.MakeGenericMethod(typeof(TDbContext), entityType);
genericMethod.Invoke(null, new [] { services, null });
#endregion DbSetFactory
.MakeGenericMethod(typeof(TDbContext), entityType);
genericMethod.Invoke(null, new [] { services, null });
#endregion DbSetFactory
}
}
RegsFromAssembly.Enqueue(reg);
}
RegsFromAssembly.Enqueue(reg);
}
public void RegisterEntity<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>>
public void RegisterEntity<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>>
#if NET
?
#endif
dbSetFactory = null)
where TDbContext : DbContext
where TEntity : class
{
void reg(IServiceCollection services)
=> services
.AddScoped<IRepository<TEntity>, DbRepository<TDbContext, TEntity>>()
.AddDbSetFactory(dbSetFactory);
dbSetFactory = null)
where TDbContext : DbContext
where TEntity : class
{
void reg(IServiceCollection services)
=> services
.AddScoped<IRepository<TEntity>, DbRepository<TDbContext, TEntity>>()
.AddDbSetFactory(dbSetFactory);
RegsEntity.Enqueue(reg);
RegsEntity.Enqueue(reg);
}
public void RegisterDbSetFactory<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>> dbSetFactory)
where TDbContext : DbContext
where TEntity : class
=> RegsDbSetFactory.Enqueue(s => s.AddDbSetFactory(dbSetFactory));
public void RegisterDefaultRepository<TDbContext>()
where TDbContext : DbContext
=> RegsRepository.Enqueue(s => s.AddScoped<IRepository, DbRepository<TDbContext>>());
}
public void RegisterDbSetFactory<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>> dbSetFactory)
where TDbContext : DbContext
where TEntity : class
=> RegsDbSetFactory.Enqueue(s => s.AddDbSetFactory(dbSetFactory));
public void RegisterDefaultRepository<TDbContext, TEntity>()
where TDbContext : DbContext
where TEntity : class
=> RegsRepository.Enqueue(s => s.AddScoped<IRepository<TEntity>, DbRepository<TDbContext, TEntity>>());
}
private static void InvokeAll<T>(this Queue<Action<T>> queue, T services)
{
while (queue.Count > 0)
queue.Dequeue().Invoke(services);
}
private static void InvokeAll<T>(this Queue<Action<T>> queue, T services)
{
while (queue.Count > 0)
queue.Dequeue().Invoke(services);
}
internal static IServiceCollection AddDbSetFactory<TDbContext, TEntity>(this IServiceCollection services, Func<TDbContext, DbSet<TEntity>>
internal static IServiceCollection AddDbSetFactory<TDbContext, TEntity>(this IServiceCollection services, Func<TDbContext, DbSet<TEntity>>
#if NET
?
#endif
create = null)
where TDbContext : DbContext
where TEntity : class
{
create = null)
where TDbContext : DbContext
where TEntity : class
{
#if NET
create ??= ctx => ctx.Set<TEntity>();
create ??= ctx => ctx.Set<TEntity>();
#elif NETFRAMEWORK
if(create is null)
create = ctx => ctx.Set<TEntity>();
if(create is null)
create = ctx => ctx.Set<TEntity>();
#endif
services.AddSingleton(_ => new DbSetFactory<TDbContext, TEntity>(create));
return services;
services.AddSingleton(_ => new DbSetFactory<TDbContext, TEntity>(create));
return services;
}
}
}
#if NETFRAMEWORK
}
#endif
}

View File

@@ -13,9 +13,9 @@
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<RepositoryType>digital data core abstractions clean architecture</RepositoryType>
<PackageTags>digital data core infrastructure clean architecture</PackageTags>
<Version>2.5.2</Version>
<AssemblyVersion>2.5.2</AssemblyVersion>
<FileVersion>2.5.2</FileVersion>
<Version>2.6.1</Version>
<AssemblyVersion>2.6.1</AssemblyVersion>
<FileVersion>2.6.1</FileVersion>
</PropertyGroup>
<ItemGroup>