EFCore
Overview
VersaTul.Data.EFCore provides reusable repository and unit-of-work base classes for projects built on Entity Framework Core.
It is useful when you want consistent repository behavior across services without rewriting the same CRUD and commit logic around DbContext in every project.
When To Use This Package
Use this package when you want to:
Build EF Core repositories from a shared base class.
Centralize
DbContextcommit and rollback behavior.Reuse sync and async CRUD operations.
Add query specifications for reusable filtering logic.
Expose no-tracking query paths when read-only performance matters.
Installation
Install the package with the .NET CLI:
dotnet add package VersaTul.Data.EFCore
Or with the Package Manager Console:
PM> NuGet\Install-Package VersaTul.Data.EFCore -Version latest
Core Types And Concepts
BaseRepository<TEntity, TKey>Reusable EF Core repository base class with sync and async CRUD support.
BaseUnitOfWorkReusable unit-of-work base class that wraps a
DbContextand providesCommit(),CommitAsync(), andRollback().IUnitOfWorkEF Core unit-of-work contract extending the broader data contract model.
IQuerySpecification<TEntity>Query criteria abstraction used to compose filtered repository reads.
DataConfigurationConfiguration type that exposes EF connection-name and connection-string access.
Key Capabilities
Repositories support sync and async CRUD paths.
Repositories expose
AsQueryable(),AsNoTrackingQueryable(), and async enumeration.Query specifications can be applied to queryable and async read methods.
BaseUnitOfWorkcentralizes save and rollback behavior over the EF Core change tracker.
Basic Example
using Microsoft.EntityFrameworkCore;
using VersaTul.Data.Contracts;
using VersaTul.Data.EFCore;
public class PlayerData
{
public int Id { get; set; }
public string Name { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class DatabaseContext : DbContext
{
private readonly IDataConnection dataConnection;
public DatabaseContext(IDataConnection dataConnection)
{
this.dataConnection = dataConnection;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(dataConnection.GetConnectionString());
}
}
public DbSet<PlayerData> Players { get; set; }
}
public class UnitOfWork : BaseUnitOfWork
{
public UnitOfWork(DatabaseContext dataContext) : base(dataContext)
{
}
}
public class PlayerRepository : BaseRepository<PlayerData, int>
{
public PlayerRepository(VersaTul.Data.EFCore.Contracts.IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}
Specification Example
using System;
using System.Linq.Expressions;
using VersaTul.Data.EFCore.Contracts;
public class ActivePlayerSpecification : IQuerySpecification<PlayerData>
{
public Expression<Func<PlayerData, bool>> Criteria => player => player.Name != null;
}
var activePlayers = await repository.GetAsync(new ActivePlayerSpecification());
var query = repository.AsQueryable(new ActivePlayerSpecification());
Notes
Rollback()reloads tracked entities from the database; it is not a database transaction rollback abstraction by itself.AsNoTrackingQueryable()andGetNoTrackingAsync()are useful for read-only paths.This package is a good fit when you want to enforce repository patterns consistently around EF Core rather than expose raw
DbContexteverywhere.