Specification.Lite is a lightweight .NET library that streamlines the implementation of the Specification pattern. It helps you encapsulate, reuse, and combine business rules, predicates, and query logic in a flexible and maintainable way.
-
Specification Pattern:
Define reusable business rules and query logic using strongly-typed specifications. Encapsulate complex predicates into composable objects. -
Query Extensions:
Apply specifications directly toIQueryableobjects for filtering, ordering, and projecting data. Supports asynchronous LINQ operations likeToListAsync,FirstOrDefaultAsync,SingleOrDefaultAsync, andAnyAsync. -
Include Expressions:
Eagerly load related entities in queries usingIncludeandThenInclude, just like in Entity Framework. -
Ordering:
Easily apply ordering to queries withOrderByandOrderByDescendingmethods on your specifications. -
Projection:
Transform entities to DTOs or other result types within the specification usingSelectandSelectMany. -
Skip & Take:
Effortlessly paginate query results usingSkipandTakeinside your specifications. -
Tracking:
Control whether entities are tracked by the context withAsTracking,AsNoTrackingandAsNoTrackingWithIdentityResolutionfor optimal performance. -
SplitQuery:
Enables the use of EF Core’sAsSplitQueryto optimize queries containing multiple includes, preventing the cartesian explosion problem. -
IgnoreQueryFilters:
Allows you to bypass global query filters (such as soft delete or multi-tenancy) by applyingIgnoreQueryFiltersin your specifications. -
IgnoreAutoIncludes:
Prevents Entity Framework Core from automatically applyingIncludestatements configured in the model by usingIgnoreAutoIncludesin your specifications. This gives you full control over which related entities are included in your queries. -
WithTag:
Annotate queries with a custom tag usingWithTagto improve query diagnostics and debugging. This is especially useful for identifying specific queries in logs or performance monitoring tools. -
Entity Framework Integration:
Seamlessly integrates with Entity Framework Core, making it easy to use specifications in your repositories or DbContext queries.
Install via NuGet Package Manager:
dotnet add package Specification.Lite --version 1.3.0Or add to your project file:
<PackageReference Include="Specification.Lite" Version="1.3.0" />Define a basic specification and use it to query active users:
// Define a simple specification for active users
public class ActiveUsersSpecification : Specification<User>
{
public ActiveUsersSpecification()
{
Query
.Include(u => u.Orders)
.Where(user => user.IsActive);
}
}
// Usage in your repository or DbContext
var spec = new ActiveUsersSpecification();
var activeUsers = await dbContext.Users.WithSpecification(spec).ToListAsync();
// Or directly using the DbContext
var activeUsers = await dbContext.Users.ToListAsync(spec);Combine filtering, includes, ordering, projection, pagination, split queries, ignoring query filters, and no-tracking:
// Complex specification: Get all active users who registered after 2024-01-01,
// include their orders (with order items), ordered by registration date descending,
// project to a custom DTO, paginate results, use split queries, ignore global query filters, and return as no-tracking.
public class RecentActiveUsersWithOrdersSpec : Specification<User, UserSummaryDto>
{
public RecentActiveUsersWithOrdersSpec(DateTime since, int skip, int take)
{
Query
.TagWith("Tag in spec query")
.Where(u => u.IsActive && u.RegisteredAt >= since)
.Include(u => u.Orders)
.ThenInclude(o => o.OrderItems)
.OrderByDescending(u => u.RegisteredAt)
.Skip(skip)
.Take(take)
.AsNoTracking()
.AsSplitQuery()
.IgnoreQueryFilters()
.Select(u => new UserSummaryDto
{
Id = u.Id,
Name = u.Name,
OrderCount = u.Orders.Count,
TotalSpent = u.Orders.Sum(o => o.TotalAmount)
});
}
}
// Usage in your application code
var spec = new RecentActiveUsersWithOrdersSpec(new DateTime(2024, 1, 1), skip: 20, take: 10);
var summaries = await dbContext.Users.WithSpecification(spec).ToListAsync();
// Or directly using the DbContext
var summaries = await dbContext.Users.ToListAsync(spec);See the examples folder.
Contributions, issues, and feature requests are welcome! or open an issue to get started.