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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DavidGroup.Core.DataAccess" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DavidGroup.Core.DataAccess" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="DavidGroup.Core.DataAccess" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DavidGroup.Core.DataAccess --version 1.5.0
                    
#r "nuget: DavidGroup.Core.DataAccess, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DavidGroup.Core.DataAccess@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DavidGroup.Core.DataAccess&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=DavidGroup.Core.DataAccess&version=1.5.0
                    
Install as a Cake Tool

DavidGroup.Core.DataAccess

Release Nuget

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?

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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 is deprecated because it has critical bugs.
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 is deprecated because it has critical bugs.
1.0.0-dev.5 65 7/8/2026
1.0.0-dev.4 60 7/8/2026
Loading failed