DavidGroup.Core.DataAccess
1.5.0
dotnet add package DavidGroup.Core.DataAccess --version 1.5.0
NuGet\Install-Package DavidGroup.Core.DataAccess -Version 1.5.0
<PackageReference Include="DavidGroup.Core.DataAccess" Version="1.5.0" />
<PackageVersion Include="DavidGroup.Core.DataAccess" Version="1.5.0" />
<PackageReference Include="DavidGroup.Core.DataAccess" />
paket add DavidGroup.Core.DataAccess --version 1.5.0
#r "nuget: DavidGroup.Core.DataAccess, 1.5.0"
#:package DavidGroup.Core.DataAccess@1.5.0
#addin nuget:?package=DavidGroup.Core.DataAccess&version=1.5.0
#tool nuget:?package=DavidGroup.Core.DataAccess&version=1.5.0
DavidGroup.Core.DataAccess
Foundation library providing data access abstractions for Entity Framework, ADO.NET, and other .NET technologies, along with common patterns and helper extensions.
🚀 Getting Started
Install NuGet Package
Using the .NET CLI:
dotnet add package DavidGroup.Core.DataAccess
Or via the Package Manager Console:
Install-Package DavidGroup.Core.DataAccess
How to use it?
Feel free to explore the samples to find practical examples for each feature. New samples are added continuously as more features are developed.
📦 Key Features
Entities
public sealed class Book : Entity<BookId>, IStronglyTypedSequentialId<BookId>,
ITimedEntity, ISoftDeletable,
ISelfManageable<Book, BookCreateModel, BookUpdateModel>
{
private Book() { }
public string Isbn { get; private init; } = null!;
public string Title { get; private init; } = null!;
public AuthorId AuthorId { get; private init; }
public Author Author { get; private init; } = null!;
public DateTime PublishedOn { get; private init; }
public decimal Price { get; private set; }
public int StockCount { get; private set; }
public DateTime CreatedAtUtc { get; set; }
public DateTime ModifiedAtUtc { get; set; }
public bool IsDeleted { get; set; }
public static OperationResult<Book> Create(BookCreateModel model)
{
return new Book
{
Isbn = model.Isbn,
Title = model.Title,
AuthorId = model.AuthorId,
PublishedOn = model.PublishedOn,
Price = model.Price,
StockCount = model.StockCount
};
}
public OperationResult Update(BookUpdateModel model)
{
Price = model.Price;
StockCount = model.StockCount;
return OperationResult.Success();
}
}
public sealed class Author : Entity<AuthorId>, IStronglyTypedSequentialId<AuthorId>,
ISelfManageable<Author, AuthorCreateModel, AuthorUpdateModel>
{
private Author() { }
public string Name { get; private set; } = null!;
public string? Biography { get; private set; }
public ICollection<Book> Books { get; private init; } = new List<Book>();
public static Author Create(AuthorCreateModel model)
{
return new Author { Name = model.Name };
}
public void Update(AuthorUpdateModel model)
{
Name = model.Name;
Biography = model.Biography;
}
}
[StronglyTypedId]
public partial struct BookId;
public record BookCreateModel(string Isbn, string Title, AuthorId AuthorId, DateTime PublishedOn, decimal Price, int StockCount);
public record BookUpdateModel(decimal Price, int StockCount);
[StronglyTypedId]
public partial struct AuthorId;
public record AuthorCreateModel(string Name);
public record AuthorUpdateModel(string Name, string? Biography);
DbContext
public class BookStoreDbContext(DbContextOptions<BookStoreDbContext> options) : DbContext(options)
{
public DbSet<Book> Books => Set<Book>();
public DbSet<Author> Authors => Set<Author>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyStronglyTypedSequentialIds(); // Sets SequentialStronglyTypedIdValueGenerator<TKey> for Id property.
// Other options
// modelBuilder.ApplySequentialGuids(); // Sets SequentialGuidValueGenerator for Id property.
// modelBuilder.ApplySqlServerSequentialIds(this); // Sets NEWSEQUENTIALID() as a default SQL Server value for Id property.
modelBuilder.ApplyQueryFiltersForSoftDeletedEntities();
}
}
Repository abstraction
public interface IBooksRepository
: IBaseRepository<Book, BookId>, IBaseAggregationRepository<Book>;
public class BooksRepository(BookStoreDbContext context)
: BaseRepository<Book, BookId>(context), IBooksRepository;
Service abstraction
public interface IBooksService : IBaseService<Book, BookId, BookCreateModel, BookUpdateModel, BookReadDto>
{
Task<OperationResult<PageData<BookReadDto>>> GetByAuthorAsync(AuthorId authorId,
PageOptions options,
string orderBy,
CancellationToken cancellationToken = default);
Task<OperationResult<InfinitePageData<BookReadDto>>> GetByAuthorAsync(AuthorId authorId,
InfinitePageOptions options,
string orderBy,
CancellationToken cancellationToken = default);
}
public class BooksService(IBooksRepository repository, IEfUnitOfWork<BookStoreDbContext> unitOfWork)
: BaseService<BookStoreDbContext, IBooksRepository,
Book, BookId,
BookCreateModel, BookUpdateModel,
BookReadDto>(repository, unitOfWork),
IBooksService
{
protected override Expression<Func<Book, BookReadDto>> ToReadDto => book => book.ToDto();
public async Task<OperationResult<PageData<BookReadDto>>> GetByAuthorAsync(AuthorId authorId,
PageOptions options,
string orderBy,
CancellationToken cancellationToken = default)
{
OperationResult<IReadOnlyList<OrderingSpecification<Book>>> orderingSpecificationsResult =
OrderingSpecification<Book>.Parse(orderBy, allowedProperties:
[
e => e.Id,
e => e.Title,
e => e.PublishedOn
]);
if (!orderingSpecificationsResult.Succeeded)
return OperationResult<PageData<BookReadDto>>.Failure(orderingSpecificationsResult.Messages[0]);
PageData<BookReadDto> result = await Repository.GetAllAsync(
options,
predicate => predicate.AuthorId == authorId,
orderingSpecifications: orderingSpecificationsResult.Value,
include: i => i.Include(e => e.Author),
selector: ToReadDto,
cancellationToken: cancellationToken);
return OperationResult<PageData<BookReadDto>>.Success(result);
}
public async Task<OperationResult<InfinitePageData<BookReadDto>>> GetByAuthorAsync(AuthorId authorId,
InfinitePageOptions options,
string orderBy,
CancellationToken cancellationToken = default)
{
OperationResult<IReadOnlyList<OrderingSpecification<Book>>> orderingSpecificationsResult =
OrderingSpecification<Book>.Parse(orderBy, allowedProperties:
[
e => e.Id,
e => e.Title,
e => e.PublishedOn
]);
if (!orderingSpecificationsResult.Succeeded)
return OperationResult<InfinitePageData<BookReadDto>>.Failure(orderingSpecificationsResult.Messages[0]);
InfinitePageData<BookReadDto> result = await Repository.GetAllAsync(
options,
orderingSpecifications: orderingSpecificationsResult.Value,
predicate => predicate.AuthorId == authorId,
include: i => i.Include(e => e.Author),
selector: ToReadDto,
cancellationToken: cancellationToken);
return OperationResult<InfinitePageData<BookReadDto>>.Success(result);
}
}
public record BookReadDto(BookId Id, string Isbn, string Title, AuthorReadDto Author, DateTime PublishedOn, decimal Price, int StockCount);
public record AuthorReadDto(AuthorId Id, string Name, string? Biography);
public static class BookMappers
{
public static BookReadDto ToDto(this Book book)
{
return new BookReadDto(book.Id,
book.Isbn,
book.Title,
new AuthorReadDto(
book.Author.Id,
book.Author.Name,
book.Author.Biography
),
book.PublishedOn,
book.Price,
book.StockCount
);
}
}
Extensions
var sqlConnectionString = builder.Configuration.GetConnectionString("BookstoreDb");
builder.Services.AddSqlServerDatabase<BookStoreDbContext>(
sqlConnectionString,
typeof(BookStoreDbContext).Assembly.GetName().Name
);
builder.Services.AddEfUnitOfWork<BookStoreDbContext>();
builder.Services.AddRepositoriesAuto();
builder.Services.AddServicesAuto();
🤝 Contributing
Found a bug? Have an idea? Want to contribute?
- Submit an issue: https://github.com/david-group-solutions/data-access/issues
- Create a pull request: https://github.com/david-group-solutions/data-access/pulls
Contributions of any size are appreciated!
📝 License
Distributed under the MIT license. See License for more information.
Copyright © 2025-2026 David Khachatryan (David Group Solutions)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- DavidGroup.Core.Utilities (>= 1.0.1)
- Elastic.Clients.Elasticsearch (>= 9.4.2)
- MassTransit (>= 8.5.7)
- MassTransit.Azure.ServiceBus.Core (>= 8.5.7)
- MassTransit.EntityFrameworkCore (>= 8.5.7)
- MassTransit.RabbitMQ (>= 8.5.7)
- Microsoft.EntityFrameworkCore (>= 10.0.9)
- Microsoft.EntityFrameworkCore.SqlServer (>= 10.0.9)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 10.0.9)
- RedLock.net (>= 2.3.2)
- Scrutor (>= 7.0.0)
-
net8.0
- DavidGroup.Core.Utilities (>= 1.0.1)
- Elastic.Clients.Elasticsearch (>= 9.4.2)
- MassTransit (>= 8.5.7)
- MassTransit.Azure.ServiceBus.Core (>= 8.5.7)
- MassTransit.EntityFrameworkCore (>= 8.3.1)
- MassTransit.RabbitMQ (>= 8.5.7)
- Microsoft.EntityFrameworkCore (>= 8.0.22)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.22)
- Microsoft.EntityFrameworkCore.SqlServer (>= 8.0.22)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 9.0.17)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.9)
- RedLock.net (>= 2.3.2)
- Scrutor (>= 7.0.0)
-
net9.0
- DavidGroup.Core.Utilities (>= 1.0.1)
- Elastic.Clients.Elasticsearch (>= 9.4.2)
- MassTransit (>= 8.5.7)
- MassTransit.Azure.ServiceBus.Core (>= 8.5.7)
- MassTransit.EntityFrameworkCore (>= 8.5.7)
- MassTransit.RabbitMQ (>= 8.5.7)
- Microsoft.EntityFrameworkCore (>= 9.0.11)
- Microsoft.EntityFrameworkCore.SqlServer (>= 9.0.11)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 9.0.17)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.9)
- RedLock.net (>= 2.3.2)
- Scrutor (>= 7.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.5.0 | 81 | 9/16/2026 | |
| 1.5.0-develop.11 | 47 | 9/16/2026 | |
| 1.4.0 | 105 | 9/6/2026 | |
| 1.4.0-develop.10 | 61 | 9/6/2026 | |
| 1.4.0-develop.9 | 70 | 9/6/2026 | |
| 1.3.0 | 95 | 9/6/2026 | |
| 1.3.0-develop.7 | 65 | 9/6/2026 | |
| 1.2.0 | 97 | 9/3/2026 | |
| 1.2.0-develop.6 | 54 | 9/2/2026 | |
| 1.2.0-develop.5 | 63 | 9/2/2026 | |
| 1.1.0 | 135 | 7/11/2026 | |
| 1.1.0-develop.4 | 62 | 7/11/2026 | |
| 1.1.0-develop.3 | 68 | 7/11/2026 | |
| 1.1.0-develop.2 | 56 | 7/11/2026 | |
| 1.0.1 | 136 | 7/9/2026 | |
| 1.0.1-develop.1 | 74 | 7/11/2026 | |
| 1.0.1-dev.9 | 73 | 7/9/2026 | |
| 1.0.0 | 132 | 7/8/2026 | |
| 1.0.0-dev.5 | 65 | 7/8/2026 | |
| 1.0.0-dev.4 | 60 | 7/8/2026 |