Skip to content

Instantly share code, notes, and snippets.

@kemsky
Last active July 4, 2023 17:10
Show Gist options
  • Save kemsky/fc60b9b6325eb349b0a9d1bb254a2b81 to your computer and use it in GitHub Desktop.
Save kemsky/fc60b9b6325eb349b0a9d1bb254a2b81 to your computer and use it in GitHub Desktop.
[Medium] Canonical specification implementation
// source: https://en.wikipedia.org/wiki/Specification_pattern
// see full implementation there
public interface ISpecification<T>
{
bool IsSatisfiedBy(T candidate);
ISpecification<T> And(ISpecification<T> other);
ISpecification<T> AndNot(ISpecification<T> other);
ISpecification<T> Or(ISpecification<T> other);
ISpecification<T> OrNot(ISpecification<T> other);
ISpecification<T> Not();
}
public abstract class LinqSpecification<T> : CompositeSpecification<T>
{
public abstract Expression<Func<T, bool>> AsExpression();
public override bool IsSatisfiedBy(T candidate) => AsExpression().Compile()(candidate);
}
public sealed class ActiveUserSpecification : LinqSpecification<User>
{
public override Expression<Func<User, bool>> AsExpression() => x => x.Active;
}
public class UserService
{
private readonly DbContext _context;
public UserService(DbContext context)
{
_context = context;
}
public Task<User> GetUser(int userId)
{
return _context.Set<User>()
.Where(x => x.userId == userId)
.Where(new ActiveUserSpecification().AsExpression()) // cool, we are using the same specification
.SingleOrDefaultAsync();
}
public Task<User> GetUserInDepartment(int userId, int departmentId)
{
return _context.Set<User>()
.Where(x => x.userId == userId)
.Where(new ActiveUserSpecification().AsExpression()) // cool, we are using the same specification
.Where(x => x.Departments.Any(z => z.Id == departmentId))
.SingleOrDefaultAsync();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment