Skip to content

Instantly share code, notes, and snippets.

@hkakutalua
Created April 10, 2018 19:44
Show Gist options
  • Select an option

  • Save hkakutalua/8c293668a1a5946fdd1c83fab9ca9fcd to your computer and use it in GitHub Desktop.

Select an option

Save hkakutalua/8c293668a1a5946fdd1c83fab9ca9fcd to your computer and use it in GitHub Desktop.
Querying using specification pattern
private async Task<Passenger> GetPermanentPassengerByPhoneNumber(PhoneNumberViewModel phoneNumberVM)
{
var phoneNumber = new PhoneNumber(phoneNumberVM.CountryCode, phoneNumberVM.Number);
var phoneCriteria = new PassengerByPhoneSpecification(phoneNumber);
var permanentPassengerCriteria = new PermanentPassengerSpecification();
return await _passengerRepository.FindOne(
phoneCriteria.AndSpecification(permanentPassengerCriteria));
}
public class PassengerByPhoneSpecification : Specification<Passenger>
{
private readonly PhoneNumber _phoneNumber;
public PassengerByPhoneSpecification(PhoneNumber phoneNumber)
{
if (phoneNumber == null)
throw new ArgumentNullException();
_phoneNumber = phoneNumber;
}
public override Expression<Func<Passenger, bool>> ToExpression()
{
return passenger => passenger.PhoneNumber == _phoneNumber;
}
}
public class PermanentPassengerSpecification : Specification<Passenger>
{
public override Expression<Func<Passenger, bool>> ToExpression()
{
return passenger => passenger.EmailConfirmed == true;
}
}
public abstract class Specification<TEntity>
where TEntity : class
{
public abstract Expression<Func<TEntity, bool>> ToExpression();
public bool IsSatisfiedBy(TEntity entity)
{
Func<TEntity, bool> predicate = ToExpression().Compile();
return predicate(entity);
}
public Specification<TEntity> AndSpecification(Specification<TEntity> specification)
{
return new AndSpecification<TEntity>(this, specification);
}
public Specification<TEntity> OrSpecification(Specification<TEntity> specification)
{
return new OrSpecification<TEntity>(this, specification);
}
}
public class AndSpecification<TEntity> : Specification<TEntity>
where TEntity : class
{
private readonly Specification<TEntity> _left;
private readonly Specification<TEntity> _right;
public AndSpecification(Specification<TEntity> left, Specification<TEntity> right)
{
_left = left;
_right = right;
}
public override Expression<Func<TEntity, bool>> ToExpression()
{
Expression<Func<TEntity, bool>> leftExpression = _left.ToExpression();
Expression<Func<TEntity, bool>> rightExpression = _right.ToExpression();
var paramExpr = Expression.Parameter(typeof(TEntity));
var exprBody = Expression.AndAlso(leftExpression.Body, rightExpression.Body);
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody);
var finalExpr = Expression.Lambda<Func<TEntity, bool>>(exprBody, paramExpr);
return finalExpr;
}
}
public class OrSpecification<TEntity> : Specification<TEntity>
where TEntity : class
{
private readonly Specification<TEntity> _left;
private readonly Specification<TEntity> _right;
public OrSpecification(Specification<TEntity> left, Specification<TEntity> right)
{
_left = left;
_right = right;
}
public override Expression<Func<TEntity, bool>> ToExpression()
{
Expression<Func<TEntity, bool>> leftExpression = _left.ToExpression();
Expression<Func<TEntity, bool>> rightExpression = _right.ToExpression();
var paramExpr = Expression.Parameter(typeof(TEntity));
var exprBody = Expression.OrElse(leftExpression.Body, rightExpression.Body);
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody);
var finalExpr = Expression.Lambda<Func<TEntity, bool>>(exprBody, paramExpr);
return finalExpr;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment