Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Baune8D/LinqBuilder
LinqBuilder is an advanced implementation of the specification pattern specifically targeting LINQ query generation.
https://github.com/Baune8D/LinqBuilder
csharp dotnet dotnet-core dotnet-standard dotnet5 dotnet6 entity-framework entity-framework-core linq specification-pattern
Last synced: 3 days ago
JSON representation
LinqBuilder is an advanced implementation of the specification pattern specifically targeting LINQ query generation.
- Host: GitHub
- URL: https://github.com/Baune8D/LinqBuilder
- Owner: Baune8D
- License: mit
- Created: 2017-07-16T22:08:12.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2024-08-01T21:42:09.000Z (4 months ago)
- Last Synced: 2024-11-08T20:18:37.275Z (7 days ago)
- Topics: csharp, dotnet, dotnet-core, dotnet-standard, dotnet5, dotnet6, entity-framework, entity-framework-core, linq, specification-pattern
- Language: C#
- Homepage:
- Size: 408 KB
- Stars: 35
- Watchers: 5
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# LinqBuilder
[![Build status](https://ci.appveyor.com/api/projects/status/v0t8rfsv0d4q3hap?svg=true)](https://ci.appveyor.com/project/Baune8D/linqbuilder)
[![codecov](https://codecov.io/gh/Baune8D/linqbuilder/branch/main/graph/badge.svg)](https://codecov.io/gh/Baune8D/linqbuilder)
[![NuGet Badge](https://buildstats.info/nuget/LinqBuilder)](https://www.nuget.org/packages/LinqBuilder)**Available on NuGet:** [https://www.nuget.org/packages/LinqBuilder/](https://www.nuget.org/packages/LinqBuilder/)
**MyGet development feed:** [https://www.myget.org/F/baunegaard/api/v3/index.json](https://www.myget.org/F/baunegaard/api/v3/index.json)LinqBuilder is based on the specification pattern.
## Table of Contents
1. [LinqBuilder Specifications](#linqbuilder-specifications)
2. [LinqBuilder OrderSpecifications](#linqbuilder-orderspecifications)
3. [LinqBuilder.EFCore / LinqBuilder.EF6](#linqbuilderefcore--linqbuilderef6)
4. [Full Example](#full-example)## LinqBuilder Specifications
### Usage
Specifications can be constructed in three different ways.**By extending Specification:**
```csharp
public class FirstnameIsFoo : Specification
{
public override Expression> AsExpression()
{
return person => person.Firstname == "Foo";
}
}ISpecification firstnameIsFoo = new FirstnameIsFoo();
```**By extending DynamicSpecification:**
```csharp
public class FirstnameIs : DynamicSpecification
{
public override Expression> AsExpression()
{
return person => person.Firstname == Value;
}
}ISpecification firstnameIsFoo = new FirstnameIs().Set("Foo");
```**By extending MultiSpecification:**
```csharp
public class FirstnameIsFoo : MultiSpecification
{
public override Expression> AsExpressionForEntity1()
{
return person => person.Firstname == "Foo";
}public override Expression> AsExpressionForEntity2()
{
return person => person.Firstname == "Foo";
}
}ISpecification firstnameIsFoo = new FirstnameIsFoo(); // First generic is default
ISpecification firstnameIsFoo = new FirstnameIsFoo().For();
ISpecification firstnameIsFoo = new FirstnameIsFoo().For();
```**By static New method:**
```csharp
ISpecification firstnameIsFoo = Specification.New(p => p.Firstname == "Foo");
// Or by alias
ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
```### Example
```csharp
var collection = new List() { ... };ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
ISpecification firstnameIsBar = Spec.New(p => p.Firstname == "Bar");ISpecification specification = firstnameIsFoo.Or(firstnameIsBar);
var result = collection.ExeSpec(specification).ToList();
// result = Collection items satisfied by specification
```
The extension ```ExeSpec``` allows all types of ```ISpecification``` to be executed on ```IQueryable``` and ```IEnumerable```.### Methods
```csharp
ISpecification specification = Spec.All(
new SomeSpecification(),
new SomeOtherSpecification(),
...
);ISpecification specification = Spec.None(
new SomeSpecification(),
new SomeOtherSpecification(),
...
);ISpecification specification = Spec.Any(
new SomeSpecification(),
new SomeOtherSpecification(),
...
);
```### Extensions
```csharp
ISpecification And(this ISpecification left, ISpecification right);
ISpecification Or(this ISpecification left, ISpecification right);
ISpecification Not(this ISpecification specification);
bool IsSatisfiedBy(this ISpecification specification, TEntity entity);
ISpecification Clone(this ISpecification specification);
```**LinqBuilder** also extends the following extensions to support ```ISpecification``` on ```IQueryable``` and ```IEnumerable```.
```csharp
IEnumerable collection = collection.Where(specification);
bool result = collection.Any(specification);
bool result = collection.All(specification);
int result = collection.Count(specification);
Entity result = collection.First(specification);
Entity result = collection.FirstOrDefault(specification);
Entity result = collection.Single(specification);
Entity result = collection.SingleOrDefault(specification);
```## LinqBuilder OrderSpecifications
### Usage
Order specifications can be constructed in almost the same way as regular specifications.**By extending OrderSpecification:**
```csharp
public class FirstnameDescending : OrderSpecification
{
public DescNumberOrderSpecification() : base(Sort.Descending) { }public override Expression> AsExpression()
{
return person => person.Firstname;
}
}ISpecification firstnameDescending = new FirstnameDescending();
```**By static New method:**
```csharp
ISpecification firstnameDescending = OrderSpecification.New(p => p.Firstname, Sort.Descending);
// Or by alias
ISpecification firstnameDescending = OrderSpec.New(p => p.Firstname, Sort.Descending);
```### Example
```csharp
var collection = new List() { ... };ISpecification firstnameDescending = OrderSpec.New(p => p.Firstname, Sort.Descending);
ISpecification lastnameDescending = OrderSpec.New(p => p.Lastname, Sort.Descending);ISpecification specification = firstnameDescending.ThenBy(lastnameDescending);
var result = collection.ExeSpec(specification).ToList();
// result = Collection ordered by descending number, then by other number
```### Methods
```csharp
ISpecification specification = OrderSpec.New(p => p.Firstname)
.Take(10);ISpecification specification = OrderSpec.New(p => p.Firstname)
.Skip(5);ISpecification specification = OrderSpec.New(p => p.Firstname)
.Paginate(2, 10); // Equals .Skip((2 - 1) * 10).Take(10)
```### Extensions
```csharp
IOrderedEnumerable collection = collection
.OrderBy(specification);
.ThenBy(otherSpecification);
```Order specifications can also be chained with regular LinqBuilder specifications.
```csharp
ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
ISpecification firstnameAscending = OrderSpec.New(p => p.Firstname);ISpecification specification = firstnameIsFoo.OrderBy(firstnameAscending);
```Chained ```OrderSpecification```'s can also be attatched to a specification later.
```csharp
ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
ISpecification firstnameAscending = OrderSpec.New(p => p.Firstname);
ISpecification lastnameAscending = OrderSpec.New(p => p.Firstname);ISpecification orderSpecification = firstnameAscending.ThenBy(lastnameAscending);
ISpecification specification = firstnameIsFoo.UseOrdering(orderSpecification);
```The following extensions will help to check what kind of ordering is applied.
```csharp
ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
ISpecification firstnameAscending = OrderSpec.New(p => p.Firstname);firstnameIsFoo.IsOrdered(); // Returns false
ISpecification specification = firstnameIsFoo.OrderBy(firstnameAscending);
specification.IsOrdered(); // Returns true
```
```csharp
ISpecification specification = Spec.New(p => p.Firstname == "Foo");
specification.HasSkip(); // Returns falseISpecification specification = specification.Skip(10);
specification.HasSkip(); // Returns true
```
```csharp
ISpecification specification = Spec.New(p => p.Firstname == "Foo");
specification.HasTake(); // Returns falseISpecification specification = specification.Take(10);
specification.HasTake(); // Returns true
```## LinqBuilder.EFCore / LinqBuilder.EF6
| Package | Version |
| -------------------|:---------------------------------------------------------------------------------------------------------------------:|
| LinqBuilder.EFCore | [![NuGet Badge](https://buildstats.info/nuget/LinqBuilder.EFCore)](https://www.nuget.org/packages/LinqBuilder.EFCore) |
| LinqBuilder.EF6 | [![NuGet Badge](https://buildstats.info/nuget/LinqBuilder.EF6)](https://www.nuget.org/packages/LinqBuilder.EF6) |### Extensions
**LinqBuilder.EF** packages extends the following extensions to support ```ISpecification```.
```csharp
bool result = await _sampleContext.Entities.AnyAsync(specification);
bool result = await _sampleContext.Entities.AllAsync(specification);
int result = await _sampleContext.Entities.CountAsync(specification);
Entity result = await _sampleContext.Entities.FirstAsync(specification);
Entity result = await _sampleContext.Entities.FirstOrDefaultAsync(specification);
Entity result = await _sampleContext.Entities.SingleAsync(specification);
Entity result = await _sampleContext.Entities.SingleOrDefaultAsync(specification);
```## Full example
```csharp
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
}public class SampleDbContext : DbContext // Simplified DbContext
{
public virtual DbSet Persons { get; set; }
}public class DbService where TEntity : class
{
private readonly DbSet _dbSet;public DbService(SampleDbContext context)
{
_dbSet = context.Set();
}public int Count(ISpecification specification)
{
return _dbSet.Count(specification);
}public List Get(ISpecification specification)
{
return _dbSet.ExeSpec(specification).ToList();
}public (List items, int count) GetAndCount(ISpecification specification)
{
return (Get(specification), Count(specification));
}
}ISpecification firstnameIsFoo = Spec.New(p => p.Firstname == "Foo");
ISpecification lastnameIsBar = Spec.New(p => p.Lastname == "Bar");
ISpecification idDescending = OrderSpec.New(p => p.Id, Sort.Descending);ISpecification specification = firstnameIsFoo.And(lastnameIsBar)
.OrderBy(idDescending)
.Paginate(1, 5); // pageNo = 1, pageSize = 5using (var context = new SampleDbContext())
{
var result = new DbService(context).GetAndCount(specification);
// result.items = Paginated list of Person's with name: Foo Bar
// result.count = Total unpaginated result count
}
```