Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primary constructor implement #402

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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 @@ -2,25 +2,19 @@

namespace Ardalis.Specification.EntityFrameworkCore;

public abstract class ContextFactoryRepositoryBaseOfT<TEntity, TContext> : IRepositoryBase<TEntity>
public abstract class ContextFactoryRepositoryBaseOfT<TEntity, TContext>(IDbContextFactory<TContext> dbContextFactory,
ISpecificationEvaluator specificationEvaluator) : IRepositoryBase<TEntity>
where TEntity : class
where TContext : DbContext
{
private readonly IDbContextFactory<TContext> _dbContextFactory;
private readonly ISpecificationEvaluator _specificationEvaluator;
private readonly IDbContextFactory<TContext> _dbContextFactory = dbContextFactory;
private readonly ISpecificationEvaluator _specificationEvaluator = specificationEvaluator;

public ContextFactoryRepositoryBaseOfT(IDbContextFactory<TContext> dbContextFactory)
: this(dbContextFactory, SpecificationEvaluator.Default)
{
}

public ContextFactoryRepositoryBaseOfT(IDbContextFactory<TContext> dbContextFactory,
ISpecificationEvaluator specificationEvaluator)
{
_dbContextFactory = dbContextFactory;
_specificationEvaluator = specificationEvaluator;
}

}

/// <inheritdoc/>
public async Task<TEntity?> GetByIdAsync<TId>(TId id, CancellationToken cancellationToken = default) where TId : notnull
{
Expand Down Expand Up @@ -205,21 +199,17 @@ public Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
throw new InvalidOperationException();
}

public async Task<int> SaveChangesAsync(TContext dbContext, CancellationToken cancellationToken = default)
{
return await dbContext.SaveChangesAsync(cancellationToken);
}
public async Task<int> SaveChangesAsync(TContext dbContext, CancellationToken cancellationToken = default)
=> await dbContext.SaveChangesAsync(cancellationToken);

/// <summary>
/// Filters the entities of <typeparamref name="TEntity"/>, to those that match the encapsulated query logic of the
/// <paramref name="specification"/>.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <returns>The filtered entities as an <see cref="IQueryable{T}"/>.</returns>
protected virtual IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification, TContext dbContext, bool evaluateCriteriaOnly = false)
{
return _specificationEvaluator.GetQuery(dbContext.Set<TEntity>().AsQueryable(), specification, evaluateCriteriaOnly);
}
protected virtual IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification, TContext dbContext, bool evaluateCriteriaOnly = false)
=> _specificationEvaluator.GetQuery(dbContext.Set<TEntity>().AsQueryable(), specification, evaluateCriteriaOnly);

/// <summary>
/// Filters all entities of <typeparamref name="TEntity" />, that matches the encapsulated query logic of the
Expand All @@ -231,8 +221,6 @@ protected virtual IQueryable<TEntity> ApplySpecification(ISpecification<TEntity>
/// <typeparam name="TResult">The type of the value returned by the projection.</typeparam>
/// <param name="specification">The encapsulated query logic.</param>
/// <returns>The filtered projected entities as an <see cref="IQueryable{T}"/>.</returns>
protected virtual IQueryable<TResult> ApplySpecification<TResult>(ISpecification<TEntity, TResult> specification, TContext dbContext)
{
return _specificationEvaluator.GetQuery(dbContext.Set<TEntity>().AsQueryable(), specification);
}
protected virtual IQueryable<TResult> ApplySpecification<TResult>(ISpecification<TEntity, TResult> specification, TContext dbContext)
=> _specificationEvaluator.GetQuery(dbContext.Set<TEntity>().AsQueryable(), specification);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@ namespace Ardalis.Specification.EntityFrameworkCore;
/// The Concrete implementation of the repository interface to create
/// </typeparam>
/// <typeparam name="TContext">The DbContext derived class to support the concrete repository</typeparam>
public class EFRepositoryFactory<TRepository, TConcreteRepository, TContext> : IRepositoryFactory<TRepository>
/// <remarks>
/// Initialises a new instance of the EFRepositoryFactory
/// </remarks>
/// <param name="dbContextFactory">The IDbContextFactory to use to generate the TContext</param>
public class EFRepositoryFactory<TRepository, TConcreteRepository, TContext>(
IDbContextFactory<TContext> dbContextFactory) : IRepositoryFactory<TRepository>
where TConcreteRepository : TRepository
where TContext : DbContext
{
private readonly IDbContextFactory<TContext> _dbContextFactory;

/// <summary>
/// Initialises a new instance of the EFRepositoryFactory
/// </summary>
/// <param name="dbContextFactory">The IDbContextFactory to use to generate the TContext</param>
public EFRepositoryFactory(IDbContextFactory<TContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
private readonly IDbContextFactory<TContext> _dbContextFactory = dbContextFactory;

/// <inheritdoc />
public TRepository CreateRepository()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,19 @@
namespace Ardalis.Specification.EntityFrameworkCore;

/// <inheritdoc/>
public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
/// <inheritdoc/>
public abstract class RepositoryBase<T>(
DbContext dbContext,
ISpecificationEvaluator specificationEvaluator) : IRepositoryBase<T> where T : class
{
protected DbContext DbContext { get; set; }
protected ISpecificationEvaluator SpecificationEvaluator { get; set; }
protected DbContext DbContext { get; set; } = dbContext;
protected ISpecificationEvaluator SpecificationEvaluator { get; set; } = specificationEvaluator;

public RepositoryBase(DbContext dbContext)
: this(dbContext, EntityFrameworkCore.SpecificationEvaluator.Default)
{
}

/// <inheritdoc/>
public RepositoryBase(DbContext dbContext, ISpecificationEvaluator specificationEvaluator)
{
DbContext = dbContext;
SpecificationEvaluator = specificationEvaluator;
}

/// <inheritdoc/>
public virtual async Task<T> AddAsync(T entity, CancellationToken cancellationToken = default)
{
Expand Down Expand Up @@ -82,60 +78,42 @@ public virtual async Task DeleteRangeAsync(ISpecification<T> specification, Canc
}

/// <inheritdoc/>
public virtual async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await DbContext.SaveChangesAsync(cancellationToken);
}
public virtual async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
=> await DbContext.SaveChangesAsync(cancellationToken);

/// <inheritdoc/>
public virtual async Task<T?> GetByIdAsync<TId>(TId id, CancellationToken cancellationToken = default) where TId : notnull
{
return await DbContext.Set<T>().FindAsync(new object[] { id }, cancellationToken: cancellationToken);
}
public virtual async Task<T?> GetByIdAsync<TId>(TId id, CancellationToken cancellationToken = default) where TId : notnull
=> await DbContext.Set<T>().FindAsync(new object[] { id }, cancellationToken: cancellationToken);

/// <inheritdoc/>
[Obsolete("Use FirstOrDefaultAsync<T> or SingleOrDefaultAsync<T> instead. The SingleOrDefaultAsync<T> can be applied only to SingleResultSpecification<T> specifications.")]
public virtual async Task<T?> GetBySpecAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}
public virtual async Task<T?> GetBySpecAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
=> await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);

/// <inheritdoc/>
[Obsolete("Use FirstOrDefaultAsync<T> or SingleOrDefaultAsync<T> instead. The SingleOrDefaultAsync<T> can be applied only to SingleResultSpecification<T> specifications.")]
public virtual async Task<TResult?> GetBySpecAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
}
public virtual async Task<TResult?> GetBySpecAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default)
=> await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);

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

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

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

/// <inheritdoc/>
public virtual async Task<List<T>> ListAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
Expand All @@ -154,45 +132,33 @@ public virtual async Task<List<TResult>> ListAsync<TResult>(ISpecification<T, TR
}

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

/// <inheritdoc/>
public virtual async Task<int> CountAsync(CancellationToken cancellationToken = default)
{
return await DbContext.Set<T>().CountAsync(cancellationToken);
}
public virtual async Task<int> CountAsync(CancellationToken cancellationToken = default)
=> await DbContext.Set<T>().CountAsync(cancellationToken);

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

/// <inheritdoc/>
public virtual async Task<bool> AnyAsync(CancellationToken cancellationToken = default)
{
return await DbContext.Set<T>().AnyAsync(cancellationToken);
}
=> await DbContext.Set<T>().AnyAsync(cancellationToken);

/// <inheritdoc/>
public virtual IAsyncEnumerable<T> AsAsyncEnumerable(ISpecification<T> specification)
{
return ApplySpecification(specification).AsAsyncEnumerable();
}
=> ApplySpecification(specification).AsAsyncEnumerable();

/// <summary>
/// Filters the entities of <typeparamref name="T"/>, to those that match the encapsulated query logic of the
/// <paramref name="specification"/>.
/// </summary>
/// <param name="specification">The encapsulated query logic.</param>
/// <returns>The filtered entities as an <see cref="IQueryable{T}"/>.</returns>
protected virtual IQueryable<T> ApplySpecification(ISpecification<T> specification, bool evaluateCriteriaOnly = false)
{
return SpecificationEvaluator.GetQuery(DbContext.Set<T>().AsQueryable(), specification, evaluateCriteriaOnly);
}
protected virtual IQueryable<T> ApplySpecification(ISpecification<T> specification, bool evaluateCriteriaOnly = false)
=> SpecificationEvaluator.GetQuery(DbContext.Set<T>().AsQueryable(), specification, evaluateCriteriaOnly);

/// <summary>
/// Filters all entities of <typeparamref name="T" />, that matches the encapsulated query logic of the
Expand All @@ -204,8 +170,6 @@ protected virtual IQueryable<T> ApplySpecification(ISpecification<T> specificati
/// <typeparam name="TResult">The type of the value returned by the projection.</typeparam>
/// <param name="specification">The encapsulated query logic.</param>
/// <returns>The filtered projected entities as an <see cref="IQueryable{T}"/>.</returns>
protected virtual IQueryable<TResult> ApplySpecification<TResult>(ISpecification<T, TResult> specification)
{
return SpecificationEvaluator.GetQuery(DbContext.Set<T>().AsQueryable(), specification);
}
protected virtual IQueryable<TResult> ApplySpecification<TResult>(ISpecification<T, TResult> specification)
=> SpecificationEvaluator.GetQuery(DbContext.Set<T>().AsQueryable(), specification);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture;

/// <inheritdoc/>
public class Repository<T> : RepositoryBase<T> where T : class
public class Repository<T>(TestDbContext dbContext,
ISpecificationEvaluator specificationEvaluator) : RepositoryBase<T>(dbContext, specificationEvaluator), RepositoryBase<T> where T : class
{
protected readonly TestDbContext dbContext;
protected readonly TestDbContext dbContext = dbContext;

public Repository(TestDbContext dbContext) : this(dbContext, EntityFrameworkCore.SpecificationEvaluator.Default)
{
}

public Repository(TestDbContext dbContext, ISpecificationEvaluator specificationEvaluator) : base(dbContext, specificationEvaluator)
{
this.dbContext = dbContext;
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
namespace Ardalis.Specification;

public class CacheSpecificationBuilder<T> : ICacheSpecificationBuilder<T> where T : class
public class CacheSpecificationBuilder<T>(
Specification<T> specification,
bool isChainDiscarded) : ICacheSpecificationBuilder<T> where T : class
{
public Specification<T> Specification { get; }
public bool IsChainDiscarded { get; set; }
public Specification<T> Specification { get; } = specification;
public bool IsChainDiscarded { get; set; } = isChainDiscarded;

public CacheSpecificationBuilder(Specification<T> specification)
: this(specification, false)
{
}

public CacheSpecificationBuilder(Specification<T> specification, bool isChainDiscarded)
{
Specification = specification;
IsChainDiscarded = isChainDiscarded;
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
namespace Ardalis.Specification;

public class IncludableSpecificationBuilder<T, TProperty> : IIncludableSpecificationBuilder<T, TProperty> where T : class
public class IncludableSpecificationBuilder<T, TProperty>(
Specification<T> specification,
bool isChainDiscarded) : IIncludableSpecificationBuilder<T, TProperty> where T : class
{
public Specification<T> Specification { get; }
public bool IsChainDiscarded { get; set; }
public Specification<T> Specification { get; } = specification;
public bool IsChainDiscarded { get; set; } = isChainDiscarded;

public IncludableSpecificationBuilder(Specification<T> specification)
: this(specification, false)
{
}

public IncludableSpecificationBuilder(Specification<T> specification, bool isChainDiscarded)
{
Specification = specification;
IsChainDiscarded = isChainDiscarded;
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
namespace Ardalis.Specification;

public class OrderedSpecificationBuilder<T> : IOrderedSpecificationBuilder<T>
public class OrderedSpecificationBuilder<T>(
Specification<T> specification,
bool isChainDiscarded) : IOrderedSpecificationBuilder<T>
{
public Specification<T> Specification { get; }
public bool IsChainDiscarded { get; set; }
public Specification<T> Specification { get; } = specification;
public bool IsChainDiscarded { get; set; } = isChainDiscarded;

public OrderedSpecificationBuilder(Specification<T> specification)
: this(specification, false)
{
}

public OrderedSpecificationBuilder(Specification<T> specification, bool isChainDiscarded)
{
Specification = specification;
IsChainDiscarded = isChainDiscarded;
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
namespace Ardalis.Specification;

public class SpecificationBuilder<T, TResult> : SpecificationBuilder<T>, ISpecificationBuilder<T, TResult>
public class SpecificationBuilder<T, TResult>(Specification<T, TResult> specification) : SpecificationBuilder<T>(specification), ISpecificationBuilder<T, TResult>
{
public new Specification<T, TResult> Specification { get; }

public SpecificationBuilder(Specification<T, TResult> specification)
: base(specification)
{
Specification = specification;
}
public new Specification<T, TResult> Specification { get; } = specification;
}

public class SpecificationBuilder<T> : ISpecificationBuilder<T>
public class SpecificationBuilder<T>(Specification<T> specification) : ISpecificationBuilder<T>
{
public Specification<T> Specification { get; }

public SpecificationBuilder(Specification<T> specification)
{
Specification = specification;
}
public Specification<T> Specification { get; } = specification;
}
2 changes: 1 addition & 1 deletion Specification/src/Ardalis.Specification/IncludeTypeEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
public enum IncludeTypeEnum
{
Include = 1,
ThenInclude = 2
ThenInclude
}
Loading