Phoesion.EFCore.PrecomputedViews
0.0.1
Prefix Reserved
dotnet add package Phoesion.EFCore.PrecomputedViews --version 0.0.1
NuGet\Install-Package Phoesion.EFCore.PrecomputedViews -Version 0.0.1
<PackageReference Include="Phoesion.EFCore.PrecomputedViews" Version="0.0.1" />
paket add Phoesion.EFCore.PrecomputedViews --version 0.0.1
#r "nuget: Phoesion.EFCore.PrecomputedViews, 0.0.1"
// Install Phoesion.EFCore.PrecomputedViews as a Cake Addin #addin nuget:?package=Phoesion.EFCore.PrecomputedViews&version=0.0.1 // Install Phoesion.EFCore.PrecomputedViews as a Cake Tool #tool nuget:?package=Phoesion.EFCore.PrecomputedViews&version=0.0.1
Phoesion.EFCore.PrecomputedViews
Phoesion.EFCore.PrecomputedViews is an Entity Framework Core library that enables the automatic computation and updating of dependent views based on changes in the database. This approach is particularly useful for scenarios where derived or computed properties need to stay in sync with related entities without manual intervention.
Features
- Automatic View Updates: Automatically recompute and update dependent properties or views when related entities are modified.
- Seamless Integration: Built on EF Core's SaveChanges pipeline, requiring minimal configuration.
- Optimized Performance: Only updates affected views, reducing unnecessary computations.
- Support for Dependency Events: Trigger recomputations based on entity events like addition, modification, or deletion.
- Custom Handlers: Easily define handlers to compute views using your business logic.
Getting Started
Prerequisites
- .NET 6 or later
- Entity Framework Core
Installation
Add the library to your project:
dotnet add package Phoesion.EFCore.PrecomputedViews
Configuration
1. Enable Precomputed Views in your DbContext
Use the AddPrecomputedViews
extension method to enable the interceptor,
either from your AddDbContext<>
in the application host builder:
builder.Services.AddDbContext<dbContext>(optionsBuilder =>
{
//setup context..
//optionsBuilder.UseSqlite("Data Source=mydb.db");
//add pre-computed views interceptor
optionsBuilder.AddPrecomputedViews();
});
or in OnConfiguring
in you dbContext class:
public class mydbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//setup context..
//optionsBuilder.UseSqlite("Data Source=mydb.db");
//Add precomputed-views interceptor
optionsBuilder.AddPrecomputedViews();
}
}
2. Define Models with Dependencies
Annotate your models with [DependsOn]
to specify the dependencies and handlers.
Example 1: Pre-compute the Enrollments.Count()
whenever an Enrollment
is added
[DependsOn<Enrollment>(DependencyEvents.Added | DependencyEvents.Removed, typeof(EnrollmentAddedRemovedHandler))]
public class Student
{
[Key]
public int Id { get; set; }
public string LastName { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
//have a pre-computed count of enrollments (this can be a read-heavy and compute-heavy count that we want to have pre-computed)
public int EnrollmentCount { get; set; }
//the handler that will update EnrollmentCount whenever an Enrollment is added/deleted
class EnrollmentAddedRemovedHandler : IComputableView<dbContext, Enrollment>
{
public async ValueTask ComputeView(dbContext context, DependencyEvents ev, IEnumerable<Enrollment> changedDependencies)
{
//find students that are affected
var studentIds = changedDependencies.Select(e => e.StudentId);
//execute update
await context.Students
.Where(s => studentIds.Contains(s.Id))
.ExecuteUpdateAsync(e => e.SetProperty(
s => s.EnrollmentCount,
s => context.Enrollments.Count(e => e.StudentId == s.Id)));
}
}
}
Example 2: Pre-compute a complex query whenever an Enrollment is added/removed (keep latest id)
[DependsOn<Enrollment>(DependencyEvents.Added | DependencyEvents.Removed, typeof(EnrollmentAddedRemovedHandler))]
public class Course
{
[Key]
public int Id { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
//This will point to the latest Enrollment added, without needing to update it manually, using the CourseViewEnrollmentAddedHandler.ComputeView() method.
public int? LatestEnrollmentIdAddedId { get; set; }
public Enrollment? LatestEnrollmentIdAdded { get; set; }
//=======================
// View handler
//=======================
class EnrollmentAddedRemovedHandler : IComputableView<dbContext, Enrollment>
{
public async ValueTask ComputeView(dbContext context, DependencyEvents ev, IEnumerable<Enrollment> changedDependencies)
{
//find courses that are affected
var courseIds = changedDependencies.Select(e => e.CourseId);
//execute update
await context.Courses
.Where(c => courseIds.Contains(c.Id))
.ExecuteUpdateAsync(e => e.SetProperty(
c => c.LatestEnrollmentIdAddedId,
c => context.Enrollments
.Where(e => e.CourseId == c.Id)
.OrderByDescending(e => e.Id)
.Select(e => (int?)e.Id)
.FirstOrDefault()));
}
}
}
Example Project
The repository includes a sample console application demonstrating how to use Phoesion.EFCore.PrecomputedViews.
Check out the Program.cs
file for detailed examples.
Contributing
Contributions are welcome! Feel free to open issues, suggest improvements, or submit pull requests.
License
This project is licensed under the MIT License.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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. |
-
net6.0
- Microsoft.EntityFrameworkCore (>= 6.0.0)
-
net7.0
- Microsoft.EntityFrameworkCore (>= 7.0.0)
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.0)
-
net9.0
- Microsoft.EntityFrameworkCore (>= 9.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 |
---|---|---|
0.0.1 | 42 | 12/18/2024 |