Skip to content

CYB3RPHO3NIX/Project-EasyEF

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Project EasyEF

EasyEF is a lightweight, generic Entity Framework Core library that implements the Repository and Unit of Work patterns, making data access simpler and more maintainable in .NET applications.

πŸš€ Features

  • Generic Repository Pattern: CRUD operations with a clean, consistent API
  • Unit of Work Pattern: Manage transactions across multiple repositories
  • Eager Loading Support: Include related entities with ease
  • Pagination: Built-in support for paginated queries
  • No-Tracking Queries: Optimize read-only operations for better performance
  • Flexible Querying: LINQ support with filtering, sorting, and custom predicates
  • Dependency Injection Ready: Easy integration with ASP.NET Core DI container
  • Type-Safe: Strongly-typed interfaces with generic constraints

πŸ“¦ Installation

Option 1: Add as Project Reference

Clone the repository and add the EasyEF.Core project to your solution:

git clone https://github.com/CYB3RPHO3NIX/Project-EasyEF.git

Then add a project reference in your .csproj file:

<ItemGroup>
  <ProjectReference Include="..\EasyEF.Core\EasyEF.Core.csproj" />
</ItemGroup>

Option 2: NuGet Package (Future)

dotnet add package EasyEF.Core

🎯 Quick Start

1. Define Your Entities

Implement the IEntity<TKey> interface on your entity classes:

using EasyEF.Core.Abstractions;

public class Employee : IEntity<int>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Username { get; set; }
    public int Age { get; set; }
    public Department EmployeeDepartment { get; set; }
}

public class Department : IEntity<int>
{
    public int Id { get; set; }
    public string DepartmentName { get; set; }
    public string Description { get; set; }
}

2. Create Your DbContext

Inherit from BaseDbContext:

using EasyEF.Core.Context;
using Microsoft.EntityFrameworkCore;

public class EmployeeDbContext : BaseDbContext
{
    public EmployeeDbContext(DbContextOptions<EmployeeDbContext> options) 
        : base(options)
    {
    }
    
    public DbSet<Employee> Employees => Set<Employee>();
    public DbSet<Department> Departments => Set<Department>();
}

3. Configure Dependency Injection (ASP.NET Core)

In your Program.cs:

using EasyEF.Core.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Register DbContext and Unit of Work
builder.Services.AddGenericDataAccess<EmployeeDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

4. Use in Your Services/Controllers

using EasyEF.Core.Abstractions;

public class EmployeeService
{
    private readonly IUnitOfWork _unitOfWork;
    
    public EmployeeService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    
    public async Task<List<Employee>> GetAllEmployeesAsync()
    {
        var repository = _unitOfWork.Repository<Employee, int>();
        return await repository.GetAsync();
    }
    
    public async Task CreateEmployeeAsync(Employee employee)
    {
        var repository = _unitOfWork.Repository<Employee, int>();
        await repository.AddAsync(employee);
        await _unitOfWork.SaveChangesAsync();
    }
}

πŸ“– Usage Examples

Basic CRUD Operations

Create

var repository = _unitOfWork.Repository<Employee, int>();

var newEmployee = new Employee 
{ 
    Name = "John Doe", 
    Username = "johndoe",
    Age = 30 
};

await repository.AddAsync(newEmployee);
await _unitOfWork.SaveChangesAsync();

Read

var repository = _unitOfWork.Repository<Employee, int>();

// Get by ID
var employee = await repository.GetByIdAsync(1);

// Get all
var allEmployees = await repository.GetAsync();

// Get with filter
var youngEmployees = await repository.GetAsync(e => e.Age < 30);

// Get single with condition
var specificEmployee = await repository.GetSingleAsync(e => e.Username == "johndoe");

Update

var repository = _unitOfWork.Repository<Employee, int>();

var employee = await repository.GetByIdAsync(1);
if (employee != null)
{
    employee.Age = 31;
    repository.Update(employee);
    await _unitOfWork.SaveChangesAsync();
}

Delete

var repository = _unitOfWork.Repository<Employee, int>();

var employee = await repository.GetByIdAsync(1);
if (employee != null)
{
    repository.Remove(employee);
    await _unitOfWork.SaveChangesAsync();
}

Advanced Queries

Eager Loading (Include Related Entities)

var repository = _unitOfWork.Repository<Employee, int>();

// Include Department when getting employee
var employee = await repository.GetByIdAsync(1, e => e.EmployeeDepartment);

// Include in filtered query
var employees = await repository.GetAsync(
    predicate: e => e.Age > 25,
    includes: e => e.EmployeeDepartment
);

Sorting

var repository = _unitOfWork.Repository<Employee, int>();

var sortedEmployees = await repository.GetAsync(
    predicate: e => e.Age > 25,
    orderBy: q => q.OrderBy(e => e.Name).ThenByDescending(e => e.Age)
);

Pagination

var repository = _unitOfWork.Repository<Employee, int>();

// Note: pageIndex is zero-based (0 = first page, 1 = second page, 2 = third page, etc.)
int pageIndex = 0; // First page
int pageSize = 10;  // Number of items per page

var pagedEmployees = await repository.GetPagedAsync(
    predicate: e => e.Age > 25,
    pageIndex: pageIndex,
    pageSize: pageSize,
    orderBy: q => q.OrderBy(e => e.Name)
);

No-Tracking Queries (Read-Only)

var repository = _unitOfWork.Repository<Employee, int>();

// Faster queries for read-only scenarios (default behavior)
var employees = await repository.GetAsync(asNoTracking: true);

// Or use Query method directly
var query = repository.Query(asNoTracking: true)
    .Where(e => e.Age > 25)
    .OrderBy(e => e.Name);
    
var result = await query.ToListAsync();

Batch Operations

var repository = _unitOfWork.Repository<Employee, int>();

// Add multiple entities
var newEmployees = new List<Employee> 
{
    new Employee { Name = "Alice", Username = "alice", Age = 28 },
    new Employee { Name = "Bob", Username = "bob", Age = 32 }
};

await repository.AddRangeAsync(newEmployees);
await _unitOfWork.SaveChangesAsync();

// Update multiple entities
var employeesToUpdate = await repository.GetAsync(e => e.Age < 30);
foreach (var emp in employeesToUpdate)
{
    emp.Age += 1;
}
repository.UpdateRange(employeesToUpdate);
await _unitOfWork.SaveChangesAsync();

// Delete multiple entities
var employeesToDelete = await repository.GetAsync(e => e.Age > 60);
repository.RemoveRange(employeesToDelete);
await _unitOfWork.SaveChangesAsync();

Working with Multiple Repositories

public async Task TransferEmployeeAsync(int employeeId, int newDepartmentId)
{
    var employeeRepo = _unitOfWork.Repository<Employee, int>();
    var departmentRepo = _unitOfWork.Repository<Department, int>();
    
    var employee = await employeeRepo.GetByIdAsync(employeeId);
    var department = await departmentRepo.GetByIdAsync(newDepartmentId);
    
    if (employee != null && department != null)
    {
        employee.EmployeeDepartment = department;
        employeeRepo.Update(employee);
        
        // Both changes are saved in one transaction
        await _unitOfWork.SaveChangesAsync();
    }
}

πŸ—οΈ Architecture

Repository Pattern

The repository pattern provides an abstraction layer between the data access logic and the business logic. Each repository handles CRUD operations for a specific entity type.

Unit of Work Pattern

The Unit of Work pattern maintains a list of objects affected by a business transaction and coordinates the writing out of changes. It ensures that all repository operations are committed in a single transaction.

Key Components

  • IEntity: Base interface for all entities
  • IRepository<TEntity, TKey>: Generic repository interface
  • IUnitOfWork: Unit of Work interface for transaction management
  • BaseDbContext: Base DbContext with automatic configuration scanning
  • GenericRepository<TEntity, TKey>: Generic repository implementation
  • UnitOfWork: Unit of Work implementation with repository caching

πŸ› οΈ Console Application Example (Without DI)

For console applications or scenarios where you're not using dependency injection:

using EasyEF.Core.UnitOfWork;
using Microsoft.EntityFrameworkCore;

string connectionString = "Server=localhost;Database=MyDb;Integrated Security=True;";

var options = new DbContextOptionsBuilder<EmployeeDbContext>()
    .UseSqlServer(connectionString)
    .Options;

using var dbContext = new EmployeeDbContext(options);
var unitOfWork = new UnitOfWork<EmployeeDbContext>(dbContext);

// Run migrations if needed
if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
{
    await dbContext.Database.MigrateAsync();
}

// Use the unit of work
var repository = unitOfWork.Repository<Employee, int>();
var employees = await repository.GetAsync(e => e.Age > 25);

foreach (var emp in employees)
{
    Console.WriteLine($"{emp.Name} - Age: {emp.Age}");
}

πŸ“‹ Requirements

  • .NET 8.0 or later
  • Entity Framework Core 8.0 or later

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. Here are some ways you can contribute:

  1. Report bugs and issues
  2. Suggest new features or enhancements
  3. Improve documentation
  4. Submit pull requests with bug fixes or new features

Development Setup

  1. Fork the repository
  2. Clone your fork
  3. Create a feature branch (git checkout -b feature/amazing-feature)
  4. Commit your changes (git commit -m 'Add some amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License.

πŸ‘€ Author

CYB3RPHO3NIX

πŸ™ Acknowledgments

  • Inspired by best practices in Entity Framework Core and the Repository/Unit of Work patterns
  • Built to simplify data access in .NET applications

πŸ“ž Support

If you have any questions or need help, please:

  • Open an issue on GitHub
  • Check the documentation above
  • Review the example project in EasyEF.Runner

Happy Coding! πŸš€

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages