Skip to content

Commit

Permalink
Add AsTracking feature. (#338)
Browse files Browse the repository at this point in the history
* Added AsTracking feature.

* Accounted for tracking order.

* Added tests.
  • Loading branch information
fiseni authored Jul 2, 2023
1 parent 393dc75 commit 80904de
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;

namespace Ardalis.Specification.EntityFrameworkCore
{
public class AsTrackingEvaluator : IEvaluator
{
private AsTrackingEvaluator() { }
public static AsTrackingEvaluator Instance { get; } = new AsTrackingEvaluator();

public bool IsCriteriaEvaluator { get; } = true;

public IQueryable<T> GetQuery<T>(IQueryable<T> query, ISpecification<T> specification) where T : class
{
if (specification.AsTracking)
{
query = query.AsTracking();
}

return query;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ public SpecificationEvaluator(bool cacheEnabled = false)
OrderEvaluator.Instance,
PaginationEvaluator.Instance,
AsNoTrackingEvaluator.Instance,
AsNoTrackingWithIdentityResolutionEvaluator.Instance,
AsTrackingEvaluator.Instance,
IgnoreQueryFiltersEvaluator.Instance,
#if !NETSTANDARD2_0
AsSplitQueryEvaluator.Instance,
AsNoTrackingWithIdentityResolutionEvaluator.Instance
#endif
AsSplitQueryEvaluator.Instance
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,35 @@ public static ICacheSpecificationBuilder<T> EnableCache<T>(
return cacheBuilder;
}

/// <summary>
/// If the entity instances are modified, this will be detected
/// by the change tracker.
/// </summary>
/// <param name="specificationBuilder"></param>
public static ISpecificationBuilder<T> AsTracking<T>(
this ISpecificationBuilder<T> specificationBuilder) where T : class
=> AsTracking(specificationBuilder, true);

/// <summary>
/// If the entity instances are modified, this will be detected
/// by the change tracker.
/// </summary>
/// <param name="specificationBuilder"></param>
/// <param name="condition">If false, the setting will be discarded.</param>
public static ISpecificationBuilder<T> AsTracking<T>(
this ISpecificationBuilder<T> specificationBuilder,
bool condition) where T : class
{
if (condition)
{
specificationBuilder.Specification.AsNoTracking = false;
specificationBuilder.Specification.AsNoTrackingWithIdentityResolution = false;
specificationBuilder.Specification.AsTracking = true;
}

return specificationBuilder;
}

/// <summary>
/// If the entity instances are modified, this will not be detected
/// by the change tracker.
Expand All @@ -391,6 +420,8 @@ public static ISpecificationBuilder<T> AsNoTracking<T>(
{
if (condition)
{
specificationBuilder.Specification.AsTracking = false;
specificationBuilder.Specification.AsNoTrackingWithIdentityResolution = false;
specificationBuilder.Specification.AsNoTracking = true;
}

Expand Down Expand Up @@ -463,6 +494,8 @@ public static ISpecificationBuilder<T> AsNoTrackingWithIdentityResolution<T>(
{
if (condition)
{
specificationBuilder.Specification.AsTracking = false;
specificationBuilder.Specification.AsNoTracking = false;
specificationBuilder.Specification.AsNoTrackingWithIdentityResolution = true;
}

Expand Down
6 changes: 6 additions & 0 deletions Specification/src/Ardalis.Specification/ISpecification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public interface ISpecification<T>
/// </summary>
string? CacheKey { get; }

/// <summary>
/// Returns whether or not the change tracker will track any of the entities
/// that are returned.
/// </summary>
bool AsTracking { get; }

/// <summary>
/// Returns whether or not the change tracker will track any of the entities
/// that are returned. When true, if the entity instances are modified, this will not be detected
Expand Down
3 changes: 3 additions & 0 deletions Specification/src/Ardalis.Specification/Specification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ public virtual bool IsSatisfiedBy(T entity)
/// <inheritdoc/>
public bool CacheEnabled { get; internal set; }

/// <inheritdoc/>
public bool AsTracking { get; internal set; } = false;

/// <inheritdoc/>
public bool AsNoTracking { get; internal set; } = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,13 @@ public void FlagsAsNoTracking_GivenSpecWithAsNoTracking()

spec.AsNoTracking.Should().Be(true);
}

[Fact]
public void FlagsAsNoTracking_GivenSpecWithAsTrackingAndEndWithAsNoTracking()
{
var spec = new CompanyByIdWithAsTrackingAsUntrackedSpec(1);

spec.AsNoTracking.Should().Be(true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,13 @@ public void FlagsAsNoTracking_GivenSpecWithAsNoTrackingWithIdentityResolution()

spec.AsNoTrackingWithIdentityResolution.Should().Be(true);
}

[Fact]
public void FlagsAsNoTracking_GivenSpecWithAsTrackingAndEndWithAsNoTrackingWithIdentityResolution()
{
var spec = new CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec(1);

spec.AsNoTrackingWithIdentityResolution.Should().Be(true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Ardalis.Specification.UnitTests.Fixture.Specs;
using FluentAssertions;
using Xunit;

namespace Ardalis.Specification.UnitTests.BuilderTests
{
public class SpecificationBuilderExtensions_AsTracking
{
[Fact]
public void DoesNothing_GivenSpecWithoutAsTracking()
{
var spec = new StoreEmptySpec();

spec.AsTracking.Should().Be(false);
}

[Fact]
public void DoesNothing_GivenAsTrackingWithFalseCondition()
{
var spec = new CompanyByIdWithFalseConditions(1);

spec.AsTracking.Should().Be(false);
}

[Fact]
public void FlagsAsTracking_GivenSpecWithAsTracking()
{
var spec = new CompanyByIdAsTrackedSpec(1);

spec.AsTracking.Should().Be(true);
}

[Fact]
public void FlagsAsTracking_GivenSpecWithAsNoTrackingAndEndWithAsTracking()
{
var spec = new CompanyByIdWithAsNoTrackingAsTrackedSpec(1);

spec.AsTracking.Should().Be(true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ardalis.Specification.UnitTests.Fixture.Entities;

namespace Ardalis.Specification.UnitTests.Fixture.Specs
{
public class CompanyByIdAsTrackedSpec : Specification<Company>, ISingleResultSpecification<Company>
{
public CompanyByIdAsTrackedSpec(int id)
{
Query.Where(company => company.Id == id).AsTracking();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ardalis.Specification.UnitTests.Fixture.Entities;

namespace Ardalis.Specification.UnitTests.Fixture.Specs
{
public class CompanyByIdWithAsNoTrackingAsTrackedSpec : Specification<Company>, ISingleResultSpecification<Company>
{
public CompanyByIdWithAsNoTrackingAsTrackedSpec(int id)
{
Query.Where(company => company.Id == id).AsNoTracking().AsNoTrackingWithIdentityResolution().AsTracking();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ardalis.Specification.UnitTests.Fixture.Entities;

namespace Ardalis.Specification.UnitTests.Fixture.Specs
{
public class CompanyByIdWithAsTrackingAsUntrackedSpec : Specification<Company>, ISingleResultSpecification<Company>
{
public CompanyByIdWithAsTrackingAsUntrackedSpec(int id)
{
Query.Where(company => company.Id == id).AsTracking().AsNoTracking();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Ardalis.Specification.UnitTests.Fixture.Entities;

namespace Ardalis.Specification.UnitTests.Fixture.Specs
{
public class CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec : Specification<Company>,
ISingleResultSpecification<Company>
{
public CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec(int id)
{
Query.Where(company => company.Id == id).AsTracking().AsNoTrackingWithIdentityResolution();
}
}
}

0 comments on commit 80904de

Please sign in to comment.