efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Cosmos: Selecting complex properties (object or collections mapped as "OwnsOne" and "OwnsMany") makes the query return the entire document

Open alexandrevribeiro opened this issue 3 years ago • 3 comments

I'm using Microsoft.EntityFrameworkCore.Cosmos 6.0.1 to perform queries against a Cosmos DB, but the problem I'm facing is that whenever I include in the Select any property that is either an object or a collection/array (mapped as "OwnsOne" and "OwnsMany"), instead of querying only the selected properties, it actually selects the entire document for EF to be able to select the complex/collection property.

Code sample

Entities

public record Litigation
{
    public string Id { get; set; }
    public string IdentifierNumber { get; set; }
    public GenericEntity City { get; set; }
    public List<GenericEntity> Subjects { get; set; }
}

public record GenericEntity
{  
    public int Id { get; set; } 
    public string Name { get; set; }
}

Entity type configuration

Note: There might be probably a way to avoid using ToJsonProperty for each Cosmos camelCase property (maybe using serialized options), but I'm not worried about that for now.

public class LitigationTypeConfiguration : IEntityTypeConfiguration<Litigation>
{
    public void Configure(EntityTypeBuilder<Litigation> builder)
    {
        builder.ToContainer(CosmosConstants.LitigationContainerName)
           .HasPartitionKey(l => l.TenantId)
           .HasNoDiscriminator();

        builder.Property(t => t.Id).ToJsonProperty("id").IsRequired();
        builder.Property(t => t.IdentifierNumber).ToJsonProperty("identifierNumber");
        builder.OwnsOne(t => t.City,
            o =>
            {
                o.ToJsonProperty("city");
                o.Property(p => p.Id).ToJsonProperty("id");
                o.Property(p => p.Name).ToJsonProperty("name");
            });
        builder.OwnsMany(t => t.Subjects,
            o =>
            {
                o.ToJsonProperty("subjects");
                o.Property(p => p.Id).ToJsonProperty("id");
                o.Property(p => p.Name).ToJsonProperty("name");
            });
    }
}

Queries sample and Results

Query sample 1) Selecting only simple properties

Query sample:

var test = _context.Litigations
	.Where(l => l.Id == id)
	.WithPartitionKey("MyPartitionKey")
	.AsNoTracking()
	.Select(l => new
	{
		l.Id,
		l.IdentifierNumber,
	}).ToList();

Result:

Note that only the c["id"] and c["identifierNumber"] were selected, as expected. image

Query sample 2) Selecting a complex object property (city)

Query sample:

var test = _context.Litigations
	.Where(l => l.Id == id)
	.WithPartitionKey("MyPartitionKey")
	.AsNoTracking()
	.Select(l => new
	{
		l.Id,
		l.IdentifierNumber,
		l.City // <-------------
	}).ToList();

Result:

In this case, the entire document is being selected (represented in the result as c), which shouldn't happen. If I copy and past this query on Azure Portal Cosmos Data Explorer, I can see it is indeed returning the entire document: image

Query sample 3) Selecting a collection/array property (subjects)

Query sample:

var test = _context.Litigations
	.Where(l => l.Id == id)
	.WithPartitionKey("MyPartitionKey")
	.AsNoTracking()
	.Select(l => new
	{
		l.Id,
		l.IdentifierNumber,
		l.Subjects // <-------------
	}).ToList();

Result:

The same behavior happening when selecting a complex object is also happening with a collection property: image

Provider and version information

EF Core version: 6.0.1 Database provider: Microsoft.EntityFrameworkCore.Cosmos 6.0.1 Target framework: .NET 6.0 Operating system: Windows IDE: Visual Studio Professional 2022

alexandrevribeiro avatar Feb 15 '22 00:02 alexandrevribeiro

Related to https://github.com/dotnet/efcore/issues/16926

For tracking queries we need to select the owner (the document in this case), however this shouldn't be necessary for non-tracking queries

AndriySvyryd avatar Feb 15 '22 19:02 AndriySvyryd

+1 for this. We're observing the same issue with a rational provider (we're using Npgsql.EntityFrameworkCore.PostgreSQL v7.0).

samisq avatar Jan 26 '23 16:01 samisq

I would also +1 this as well

relfman-cmg avatar Jan 26 '23 17:01 relfman-cmg