Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public virtual async Task<T> AddAsync(T entity, CancellationToken cancellationTo

return entity;
}

/// <inheritdoc/>
public virtual async Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
Expand All @@ -51,14 +52,26 @@ public virtual async Task UpdateAsync(T entity, CancellationToken cancellationTo

await SaveChangesAsync(cancellationToken);
}


/// <inheritdoc/>
public virtual async Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
foreach (var entity in entities)
{
dbContext.Entry(entity).State = EntityState.Modified;
}

await SaveChangesAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
{
dbContext.Set<T>().Remove(entity);

await SaveChangesAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
Expand All @@ -78,29 +91,59 @@ public virtual async Task<T> GetByIdAsync<TId>(TId id, CancellationToken cancell
{
return await dbContext.Set<T>().FindAsync(cancellationToken: cancellationToken, new object[] { id });
}

/// <inheritdoc/>
public virtual async Task<T> GetBySpecAsync<Spec>(Spec specification, CancellationToken cancellationToken = default) where Spec : ISpecification<T>, ISingleResultSpecification
[Obsolete]
public virtual async Task<T> GetBySpecAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
[Obsolete]
public virtual async Task<TResult> GetBySpecAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<T> FirstOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<TResult> FirstOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<T> SingleOrDefaultAsync(ISingleResultSpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<TResult> SingleOrDefaultAsync<TResult>(ISingleResultSpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<List<T>> ListAsync(CancellationToken cancellationToken = default)
{
return await dbContext.Set<T>().ToListAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<List<T>> ListAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
var queryResult = await ApplySpecification(specification).ToListAsync(cancellationToken);

return specification.PostProcessingAction == null ? queryResult : specification.PostProcessingAction(queryResult).ToList();
}

/// <inheritdoc/>
public virtual async Task<List<TResult>> ListAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
Expand Down Expand Up @@ -143,6 +186,7 @@ protected virtual IQueryable<T> ApplySpecification(ISpecification<T> specificati
{
return specificationEvaluator.GetQuery(dbContext.Set<T>().AsQueryable(), specification, evaluateCriteriaOnly);
}

/// <summary>
/// Filters all entities of <typeparamref name="T" />, that matches the encapsulated query logic of the
/// <paramref name="specification"/>, from the database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public virtual async Task<T> AddAsync(T entity, CancellationToken cancellationTo

return entity;
}

/// <inheritdoc/>
public virtual async Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
Expand All @@ -51,14 +52,23 @@ public virtual async Task UpdateAsync(T entity, CancellationToken cancellationTo

await SaveChangesAsync(cancellationToken);
}


/// <inheritdoc/>
public virtual async Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
dbContext.Set<T>().UpdateRange(entities);

await SaveChangesAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
{
dbContext.Set<T>().Remove(entity);

await SaveChangesAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
{
Expand All @@ -78,29 +88,59 @@ public virtual async Task<int> SaveChangesAsync(CancellationToken cancellationTo
{
return await dbContext.Set<T>().FindAsync(new object[] { id }, cancellationToken: cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<T?> GetBySpecAsync<Spec>(Spec specification, CancellationToken cancellationToken = default) where Spec : ISpecification<T>, ISingleResultSpecification
[Obsolete]
public virtual async Task<T?> GetBySpecAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
[Obsolete]
public virtual async Task<TResult?> GetBySpecAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<T?> FirstOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<TResult?> FirstOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<T?> SingleOrDefaultAsync(ISingleResultSpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<TResult?> SingleOrDefaultAsync<TResult>(ISingleResultSpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<List<T>> ListAsync(CancellationToken cancellationToken = default)
{
return await dbContext.Set<T>().ToListAsync(cancellationToken);
}

/// <inheritdoc/>
public virtual async Task<List<T>> ListAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
var queryResult = await ApplySpecification(specification).ToListAsync(cancellationToken);

return specification.PostProcessingAction == null ? queryResult : specification.PostProcessingAction(queryResult).ToList();
}

/// <inheritdoc/>
public virtual async Task<List<TResult>> ListAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
Expand Down Expand Up @@ -143,6 +183,7 @@ protected virtual IQueryable<T> ApplySpecification(ISpecification<T> specificati
{
return specificationEvaluator.GetQuery(dbContext.Set<T>().AsQueryable(), specification, evaluateCriteriaOnly);
}

/// <summary>
/// Filters all entities of <typeparamref name="T" />, that matches the encapsulated query logic of the
/// <paramref name="specification"/>, from the database.
Expand Down
51 changes: 49 additions & 2 deletions Specification/src/Ardalis.Specification/IReadRepositoryBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -32,7 +33,8 @@ public interface IReadRepositoryBase<T> where T : class
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="T" />, or <see langword="null"/>.
/// </returns>
Task<T?> GetBySpecAsync<Spec>(Spec specification, CancellationToken cancellationToken = default) where Spec : ISingleResultSpecification, ISpecification<T>;
[Obsolete]
Task<T?> GetBySpecAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Finds an entity that matches the encapsulated query logic of the <paramref name="specification"/>.
Expand All @@ -43,8 +45,53 @@ public interface IReadRepositoryBase<T> where T : class
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="TResult" />.
/// </returns>
[Obsolete]
Task<TResult?> GetBySpecAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Returns the first element of a sequence, or a default value if the sequence contains no elements.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="T" />, or <see langword="null"/>.
/// </returns>
Task<T?> FirstOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Returns the first element of a sequence, or a default value if the sequence contains no elements.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="TResult" />, or <see langword="null"/>.
/// </returns>
Task<TResult?> FirstOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="T" />, or <see langword="null"/>.
/// </returns>
Task<T?> SingleOrDefaultAsync(ISingleResultSpecification<T> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <typeparamref name="TResult" />, or <see langword="null"/>.
/// </returns>
Task<TResult?> SingleOrDefaultAsync<TResult>(ISingleResultSpecification<T, TResult> specification, CancellationToken cancellationToken = default);

/// <summary>
/// Finds all entities of <typeparamref name="T" /> from the database.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public interface IRepositoryBase<T> : IReadRepositoryBase<T> where T : class
/// The task result contains the <typeparamref name="T" />.
/// </returns>
Task<T> AddAsync(T entity, CancellationToken cancellationToken = default);

/// <summary>
/// Adds the given entities in the database
/// </summary>
Expand All @@ -33,24 +34,36 @@ public interface IRepositoryBase<T> : IReadRepositoryBase<T> where T : class
/// The task result contains the <typeparamref name="IEnumerable<T>" />.
/// </returns>
Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);

/// <summary>
/// Updates an entity in the database
/// </summary>
/// <param name="entity">The entity to update.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);

/// <summary>
/// Updates the given entities in the database
/// </summary>
/// <param name="entities">The entities to update.</param>
/// <param name="cancellationToken"></param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);

/// <summary>
/// Removes an entity in the database
/// </summary>
/// <param name="entity">The entity to delete.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task DeleteAsync(T entity, CancellationToken cancellationToken = default);

/// <summary>
/// Removes the given entities in the database
/// </summary>
/// <param name="entities">The entities to remove.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);

/// <summary>
/// Persists changes to the database.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,27 @@
{
/// <summary>
/// A marker interface for specifications that are meant to return a single entity. Used to constrain methods
/// that accept a Specification and return a single result rather than a collection of results
/// that accept a Specification and return a single result rather than a collection of results.
/// </summary>
public interface ISingleResultSpecification
{
}

/// <summary>
/// Encapsulates query logic for <typeparamref name="T"/>. It is meant to return a single result.
/// </summary>
/// <typeparam name="T">The type being queried against.</typeparam>
public interface ISingleResultSpecification<T> : ISpecification<T>, ISingleResultSpecification
{
}

/// <summary>
/// Encapsulates query logic for <typeparamref name="T"/>,
/// and projects the result into <typeparamref name="TResult"/>. It is meant to return a single result.
/// </summary>
/// <typeparam name="T">The type being queried against.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
public interface ISingleResultSpecification<T, TResult> : ISpecification<T, TResult>, ISingleResultSpecification
{
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Ardalis.Specification
{
/// <inheritdoc cref="ISingleResultSpecification{T}"/>
public class SingleResultSpecification<T> : Specification<T>, ISingleResultSpecification<T>
{
}

/// <inheritdoc cref="ISingleResultSpecification{T, TResult}"/>
public class SingleResultSpecification<T, TResult> : Specification<T, TResult>, ISingleResultSpecification<T, TResult>
{
}
}
Loading