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

[6.0] Respect AsNoTrackingWithIdentityResolution in AsTracking method #26233

Merged
merged 2 commits into from
Oct 3, 2021
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
10 changes: 7 additions & 3 deletions src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2983,9 +2983,13 @@ public static IQueryable<TEntity> AsTracking<TEntity>(
this IQueryable<TEntity> source,
QueryTrackingBehavior track)
where TEntity : class
=> track == QueryTrackingBehavior.TrackAll
? source.AsTracking()
: source.AsNoTracking();
=> track switch
{
QueryTrackingBehavior.TrackAll => source.AsTracking(),
QueryTrackingBehavior.NoTracking => source.AsNoTracking(),
QueryTrackingBehavior.NoTrackingWithIdentityResolution => source.AsNoTrackingWithIdentityResolution(),
_ => throw new ArgumentOutOfRangeException(nameof(track))
};

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4130,15 +4130,15 @@ FROM root c
}

[ConditionalTheory(Skip = "Issue #17246")]
public override Task Perform_identity_resolution_reuses_same_instances(bool async)
public override Task Perform_identity_resolution_reuses_same_instances(bool async, bool useAsTracking)
{
return base.Perform_identity_resolution_reuses_same_instances(async);
return base.Perform_identity_resolution_reuses_same_instances(async, useAsTracking);
}

[ConditionalTheory(Skip = "Issue #17246")]
public override Task Perform_identity_resolution_reuses_same_instances_across_joins(bool async)
public override Task Perform_identity_resolution_reuses_same_instances_across_joins(bool async, bool useAsTracking)
{
return base.Perform_identity_resolution_reuses_same_instances_across_joins(async);
return base.Perform_identity_resolution_reuses_same_instances_across_joins(async, useAsTracking);
}

[ConditionalTheory(Skip = "Issue #17246")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,9 +461,9 @@ public override async Task Can_query_indexer_property_on_owned_collection(bool i
}

[ConditionalTheory(Skip = "No SelectMany, No Ability to Include navigation back to owner #17246")]
public override Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(bool async)
public override Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(bool async, bool useAsTracking)
{
return base.NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(async);
return base.NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(async, useAsTracking);
}

[ConditionalTheory(Skip = "No Composite index to process custom ordering #17246")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ var orders
public override Task Include_with_cycle_does_not_throw_when_AsNoTrackingWithIdentityResolution(bool async)
=> Task.CompletedTask;

public override Task Include_with_cycle_does_not_throw_when_AsTracking_NoTrackingWithIdentityResolution(bool async)
=> Task.CompletedTask;

protected override bool IgnoreEntryCount
=> true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1650,6 +1650,18 @@ where i.OrderID < 10800
.AsNoTrackingWithIdentityResolution());
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Include_with_cycle_does_not_throw_when_AsTracking_NoTrackingWithIdentityResolution(bool async)
{
return AssertQuery(
async,
ss => (from i in ss.Set<Order>().Include(o => o.Customer.Orders)
where i.OrderID < 10800
select i)
.AsTracking(QueryTrackingBehavior.NoTrackingWithIdentityResolution));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Outer_idenfier_correctly_determined_when_doing_include_on_right_side_of_left_join(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6072,16 +6072,22 @@ public virtual Task String_include_on_incorrect_property_throws(bool async)
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Perform_identity_resolution_reuses_same_instances(bool async)
[InlineData(false, false)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
public virtual async Task Perform_identity_resolution_reuses_same_instances(bool async, bool useAsTracking)
{
using var context = CreateContext();
var orderIds = context.Customers.Where(c => c.CustomerID == "ALFKI")
.SelectMany(c => c.Orders).Select(o => o.OrderID).ToList();

var query = context.Orders.Where(o => orderIds.Contains(o.OrderID))
.Select(o => o.Customer)
.AsNoTrackingWithIdentityResolution();
.Select(o => o.Customer);

query = useAsTracking
? query.AsTracking(QueryTrackingBehavior.NoTrackingWithIdentityResolution)
: query.AsNoTrackingWithIdentityResolution();

var result = async
? await query.ToListAsync()
Expand All @@ -6094,16 +6100,22 @@ public virtual async Task Perform_identity_resolution_reuses_same_instances(bool
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Perform_identity_resolution_reuses_same_instances_across_joins(bool async)
[InlineData(false, false)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
public virtual async Task Perform_identity_resolution_reuses_same_instances_across_joins(bool async, bool useAsTracking)
{
using var context = CreateContext();

var query = (from c in context.Customers.Where(c => c.CustomerID.StartsWith("A"))
join o in context.Orders.Where(o => o.OrderID < 10500).Include(o => o.Customer)
on c.CustomerID equals o.CustomerID
select new { c, o })
.AsNoTrackingWithIdentityResolution();
select new { c, o });

query = useAsTracking
? query.AsTracking(QueryTrackingBehavior.NoTrackingWithIdentityResolution)
: query.AsNoTrackingWithIdentityResolution();

var result = async
? await query.ToListAsync()
Expand Down
27 changes: 21 additions & 6 deletions test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,18 @@ public virtual async Task Throw_for_owned_entities_without_owner_in_tracking_que
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Owned_entity_without_owner_does_not_throw_for_identity_resolution(bool async)
[InlineData(false, false)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
public virtual async Task Owned_entity_without_owner_does_not_throw_for_identity_resolution(bool async, bool useAsTracking)
{
using var context = CreateContext();
var query = context.Set<OwnedPerson>().Select(e => e.PersonAddress).AsNoTrackingWithIdentityResolution();
var query = context.Set<OwnedPerson>().Select(e => e.PersonAddress);

query = useAsTracking
? query.AsTracking(QueryTrackingBehavior.NoTrackingWithIdentityResolution)
: query.AsNoTrackingWithIdentityResolution();

var result = async
? await query.ToListAsync()
Expand Down Expand Up @@ -774,11 +781,19 @@ public virtual async Task NoTracking_Include_with_cycles_throws(bool async)
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(bool async)
[InlineData(false, false)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
public virtual async Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(
bool async, bool useAsTracking)
{
using var context = CreateContext();
var query = context.Set<OwnedPerson>().SelectMany(op => op.Orders).Include(o => o.Client).AsNoTrackingWithIdentityResolution();
var includableQuery = context.Set<OwnedPerson>().SelectMany(op => op.Orders).Include(o => o.Client);

var query = useAsTracking
? includableQuery.AsTracking(QueryTrackingBehavior.NoTrackingWithIdentityResolution)
: includableQuery.AsNoTrackingWithIdentityResolution();

var result = async
? await query.ToListAsync()
Expand Down