Sisusa.Data.EFCore
3.0.0
See the version list below for details.
dotnet add package Sisusa.Data.EFCore --version 3.0.0
NuGet\Install-Package Sisusa.Data.EFCore -Version 3.0.0
<PackageReference Include="Sisusa.Data.EFCore" Version="3.0.0" />
<PackageVersion Include="Sisusa.Data.EFCore" Version="3.0.0" />
<PackageReference Include="Sisusa.Data.EFCore" />
paket add Sisusa.Data.EFCore --version 3.0.0
#r "nuget: Sisusa.Data.EFCore, 3.0.0"
#addin nuget:?package=Sisusa.Data.EFCore&version=3.0.0
#tool nuget:?package=Sisusa.Data.EFCore&version=3.0.0
User Documentation for Repository Pattern Implementation in Sisusa.Data.EFCore
This document provides a comprehensive guide for using the SimpleRepository
, BaseRepository
, and new query-related classes from the Sisusa.Data.EFCore
namespace. These classes implement the repository pattern for managing data access in applications using Entity Framework Core.
Overview
Purpose
The repository pattern abstracts data access logic, providing a consistent and reusable interface for performing CRUD operations on database entities. This implementation supports generic data access for entities identified by a primary key (TId
).
Key Components
SimpleRepository
- Provides basic CRUD and query operations.
- Abstraction over
DbSet
.
BaseRepository
- Extends
SimpleRepository
with additional functionality like managing proxy entities. - Supports creation of proxy objects using a
Func<TId, TEntity>
delegate to simplify some operationsDelete
,Update
.
- Extends
DataSourceContext
- Extends
DbContext
to manage entity sets (EntitySet<T>
). - Supports transaction management ;
bypasses the
Database
call, so that instead of
var transaction = await context.Database.BeginTransactionAsync();
we can simply do:
var transaction = await context.BeginTransactionAsync();
Remember, the goal is to have a shared
interface
that can work for any data source (SQL, NoSQL, File, etc.) some of which may not have the concept of aDatabase
.- Extends
Query<TEntity>
- Provides a fluent interface for building queries with filtering, ordering, and projections.
- This is SQL/EF specific and is simply a wrapper around functionality that EF already provides:
//EF native var membersOver20 = await context.Set<ClubMembers>() .Where(p => (TimeService.CurrentYear - p.DateOfBirth.Year) > 20) .OrderBy(p => p.Id) .ThenBy(p => p.Name) .Include(p => p.PaymentInfo).ToList(); //using the Query class becomes var membersOver20 = await Query<ClubMembers>.UsingContext(context). .Where(p => (TimeService.CurrentYear - p.DateOfBirth.Year) > 20) .OrderBy(p => p.Id) .ThenBy(p => p.Name) .Include(p => p.PaymentInfo).ToListAsync(); //aim is to have more verbose and readable code
EntitySet<T>
- An implementation of
IEntityCollection<T>
for use with an EF context, enabling advanced querying and entity management.
var members = context.Entities<ClubMembers>();> //same as var members = context.Set<ClubMembers>();
- An implementation of
Prerequisites
Installation
Ensure you have the following packages installed:
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.SqlServer (or other database provider)
Setup
Configure the DataSourceContext
in your Startup.cs
or Program.cs
file:
services.AddDbContext<DataSourceContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped(typeof(IRepository<,>), typeof(SimpleRepository<,>));
services.AddScoped(typeof(BaseRepository<,>));
Class Descriptions
SimpleRepository
The SimpleRepository
class provides generic CRUD operations for entities.
Key Methods
AddNewAsync
public virtual Task AddNewAsync(TEntity entity)
Adds a new entity to the database.
FindAllAsync
public virtual Task<List<TEntity>> FindAllAsync()
Retrieves all entities from the database.
FindByIdAsync
public virtual Task<TEntity?> FindByIdAsync(TId id)
Retrieves an entity by its primary key.
UpdateAsync
public virtual Task UpdateAsync(TEntity entity)
Updates an existing entity in the database.
DeleteByIdAsync
public virtual Task DeleteByIdAsync(TId id)
Deletes an entity by its primary key.
BaseRepository
The BaseRepository
class extends SimpleRepository
to include proxy creation and additional entity management capabilities.
Key Methods
AddNewAsync Behaves the same as in
SimpleRepository
but supports additional logic for proxies.UpdateByIdAsync
public virtual Task UpdateByIdAsync(TId id, TEntity updatedEntity)
Updates an entity identified by its primary key.
HasByIdAsync
public virtual Task<bool> HasByIdAsync(TId id)
Checks if an entity exists by its primary key.
Query<TEntity>
The Query<TEntity>
class provides a fluent API for building queries with filtering, ordering, and projections.
Key Methods
Where
public Query<TEntity> Where(Expression<Func<TEntity, bool>> predicate)
Adds a filtering condition to the query.
OrderBy
public Query<TEntity> OrderBy(Expression<Func<TEntity, object>> keySelector, OrderMode mode = OrderMode.Ascending)
Adds an ordering to the query.
ThenBy
public Query<TEntity> ThenBy(Expression<Func<TEntity, object>> keySelector, OrderMode mode = OrderMode.Ascending)
Adds a secondary ordering to the query.
Include
public Query<TEntity> Include(Expression<Func<TEntity, object>> navigationPropertyPath)
Includes a navigation property in the query.
ProjectTo
public IQueryable<TNew> ProjectTo<TNew>(Expression<Func<TEntity, TNew>> selector) where TNew : class
Projects the query results to a new type.
EntitySet<T>
The EntitySet<T>
class provides advanced querying and entity management capabilities.
Key Methods
AddAsync
public async Task AddAsync(T entity, CancellationToken cancellationToken = default)
Adds a new entity to the set.
RemoveAsync
public async Task RemoveAsync(T entity, CancellationToken cancellationToken = default)
Removes an entity from the set.
CountAsync
public async Task<int> CountAsync()
Returns the count of entities in the set.
Usage Examples
1. SimpleRepository
: Basic CRUD Operations
Scenario
Suppose we have an Employee
entity with a primary key of type int
. We need to manage employees using the repository.
Setup
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Department { get; set; }
}
var repository = new SimpleRepository<Employee, int>(context);
Examples
Add a New Employee
var newEmployee = new Employee { Name = "John Doe", Department = "HR" }; await repository.AddNewAsync(newEmployee);
Retrieve All Employees
var employees = await repository.FindAllAsync();
Retrieve an Employee by ID
var employee = await repository.FindByIdAsync(1);
Update an Employee
var employee = await repository.FindByIdAsync(1); if (employee != null) { employee.Department = "Finance"; await repository.UpdateAsync(employee); }
Delete an Employee
await repository.DeleteByIdAsync(1);
2. BaseRepository
: Advanced Operations with Proxy Creation
Scenario
Suppose we have a Product
entity. The BaseRepository
allows efficient handling of proxy objects for managing data.
Setup
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
var repository = new BaseRepository<Product, Guid>(context, id => new Product { Id = id });
Examples
Add a New Product
var product = new Product { Id = Guid.NewGuid(), Name = "Laptop", Price = 1200.00m }; await repository.AddNewAsync(product);
Update a Product by ID
var productId = Guid.NewGuid(); var updatedProduct = new Product { Name = "Gaming Laptop", Price = 1500.00m }; await repository.UpdateByIdAsync(productId, updatedProduct);
Delete a Product by ID
var productId = Guid.NewGuid(); await repository.DeleteByIdAsync(productId);
Check if a Product Exists
var exists = await repository.HasByIdAsync(productId);
3. Query<TEntity>
: Building Queries
Scenario
Using the Query<TEntity>
class to filter and order results.
Setup
var query = Query<Product>.FromContext(context)
.Where(p => p.Price > 1000)
.OrderBy(p => p.Name);
Example
- Get Products
var products = await query.GetCompiled().ToListAsync();
4. Transaction Management with DataSourceContext
Scenario
You want to ensure atomicity when performing multiple operations.
Example
using var transaction = await context.BeginTransactionAsync();
try
{
await repository.AddNewAsync(new Employee { Name = "Alice", Department = "IT" });
await repository.AddNewAsync(new Employee { Name = "Bob", Department = "Finance" });
await context.SaveChangesAsync();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
Best Practices
Validation
- Ensure inputs (e.g.,
id
andentity
) are not null.
- Ensure inputs (e.g.,
Error Handling
- Handle
EntityNotFoundException
gracefully when performing updates or deletions.
- Handle
Transaction Usage
- Wrap multiple related operations in a transaction to maintain consistency.
Entity Set Configuration
- Customize
EntitySet
logic to suit specific data access requirements.
- Customize
Conclusion
The SimpleRepository
, BaseRepository
, Query<TEntity>
, and EntitySet<T>
classes provide powerful abstractions for managing database operations. Their extensible design supports a variety of use cases, making data access straightforward and maintainable. Use these classes to simplify your data layer and focus on core business logic.
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 was computed. 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 was computed. 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. |
-
net8.0
- Microsoft.EntityFrameworkCore (>= 9.0.4)
- Microsoft.EntityFrameworkCore.Relational (>= 9.0.4)
- Sisusa.Data.Contracts (>= 4.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.
Breaking updates - reduced the layers over EF and used raw EF where possible. e.g, methods expecting EntitySet<T> now work with DbSet<T>. Added dependency to EFCore.BulkExtensions - haven't got around to making that work yet. Streamlined the BatchInsertManager(and renamed)