Cosmos: Projection binding initialize empty collections#37971
Cosmos: Projection binding initialize empty collections#37971roji merged 4 commits intodotnet:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes Cosmos projection materialization so that included/projection-bound empty collection navigations are initialized as empty collections (instead of remaining null), allowing the owned-navigation association tests to use the shared base asserters again.
Changes:
- Initialize collection navigations when
relatedEntitiesis non-null (including the empty-enumerable case) during include materialization. - Remove the Cosmos-specific test asserter overrides that were compensating for #36577.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/EFCore.Cosmos.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCosmosFixture.cs | Removes workaround asserters for #36577 now that Cosmos behavior is corrected. |
| src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs | Ensures collection navigations are created for materialization when the related-entities enumerable exists (even if empty), and removes the prior initialize delegate plumbing. |
...hapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Thanks @JoasE, looks great.
I'll add a breaking change note for this.
/cc @AndriySvyryd let me know if you have any memory around this, or any objection to this fix (which is a breaking change, though a bug fix).
|
@AndriySvyryd @roji Good to note that both before and after this change a null value in the json will not be materialized to null but to an empty collection. Not sure if that is a bug or not. Should I create an issue? [ConditionalFact]
public virtual async Task Can_set_embedded_collection_null()
{
var options = await Fixture.CreateOptions(seed: false);
var person = new Person
{
Id = 1,
Addresses = null,
};
using var context = new EmbeddedTransportationContext(options);
await context.AddAsync(person);
await context.SaveChangesAsync();
context.ChangeTracker.Clear();
var entity = await context.Set<Person>().FirstAsync();
Assert.Null(entity.Addresses); // Fails: Assert.Null() Failure: Value is not null, Actual: []
} |
Hmm, I don't think we have clear behavior in this case - since EF shouldn't ever produce a null JSON property for a collection (but only an empty JSON array), this is "undefined". It's good to have an issue for thinking what we want to do here: I'd check (a) what our relational JSON behavior does, and (b) what System.Text.Json does. |
No objections.
We don't support it yet. #35916 |
During projection binding, IncludeCollection is invoked which will enumerate a select over a projection binding lambda for the collection type. If tracking is enabled, change tracking will initialize the collection if not set during the enumeration. If tracking is not enabled, a fixup is invoked which will initialize the collection if not set. If no items are in the list, no enumeration is done and no fixup or change tracking code is ran, thus the collection will never be initialized.
Simple fix is always initialize collection in IncludeCollection if value is not null
Closes: #36577