I am writing an asp.net web api and I am using a cqrs pattern with mediator, repository pattern + unit of work, and now I want to add a specification pattern, I already implemented the pattern like this (showing a part of each class):
public abstract class BaseSpecification<T> : ISpecification<T>
{
protected BaseSpecification(Expression<Func<T, bool>> criteria)
{
Criteria = criteria;
}
protected BaseSpecification()
{
}
public Expression<Func<T, bool>> Criteria { get; }
public List<Expression<Func<T, object>>> Includes { get; } = new();
protected virtual void AddInclude(Expression<Func<T, object>> includeExpression)
{
Includes.Add(includeExpression);
}
}
Specification to include related entities:
public MediaIncludePeopleAndGenres(int mediaId)
: base(x => x.MediaId == mediaId)
{
AddInclude(x => x.MediaGenres);
AddInclude(x => x.MediaPeople);
}
Specification extension class for entity framework context
public static IQueryable<T> Specify<T>(this IQueryable<T> query, ISpecification<T> spec) where T : class
{
var resultWithIncludes = spec
.Includes
.Aggregate(query, (current, include) => current.Include(include));
return resultWithIncludes.Where(spec.Criteria);
}
Method in repository class:
public Task<Media?> GetMediaByIdAsync(int id)
{
return _context.Media
.Specify(new MediaIncludePeopleAndGenres(id))
.FirstOrDefaultAsync();
}
It works just as I expected, but I didn't find a similar approach for commands (like post or put), what functionality should I put in the specification? Can I please get an example according to my approach? Now I am calling post media method like this: repository class
public void AddSingleMedia(Media media)
{
_context.Media.Add(media);
}
P.S: I didn't show commands or queries handlers, because I only do mapping there, and calling the repository methods.
Aucun commentaire:
Enregistrer un commentaire