dotnet / dotnet/efcore

Could queries with navigation properties not produce joins if using only primary keys?

Open
#28,077 0 comments 6 reactions 0 assignees View on GitHub
area-perf area-query customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

I have a model like this:
```C#
public class Warranty {
// Primary key in Fluent API
public int Id { get; set; }

// DATA
[...]

// Navigation
public ICollection? Conditions { get; set; }
}

public class WarrantyCondition {
// Composite key in Fluent API
public int WarrantyId { get; set; }
public int Id { get; set; }

// DATA
[...]

// Navigation
public Warranty? Warranty{ get; set; }
public ICollection? Products { get; set; }
}

public class WarrantyProduct {
// Composite key in Fluent API
public int ConditionWarrantyId { get; set; }
public int ConditionId { get; set; }
public int ProductId { get; set; }

// DATA
[...]

// Navigation
public WarrantyCondition? Condition { get; set; }
public Product? Product { get; set; }
}
```

With tables looking like this:
![Warranty](https://user-images.githubusercontent.com/6189813/169791922-41483986-92c5-4a9a-90a2-6497551dffd3.png)

![WarrantyCondition](https://user-images.githubusercontent.com/6189813/169791952-f24fa80c-4271-455c-a3d3-1ced695ddc74.png)

![WarrantyProduct](https://user-images.githubusercontent.com/6189813/169791975-86bcced3-abac-427f-954c-274e9bbf120c.png)

When querying by using a navigation property like this:
```C#
dbContext.Set().Where(p => p.Condition.Warranty.Id == 1).ToArray()
```

I get a resulting query like this:
```SQL
SELECT [w].[ConditionWarrantyId], [w].[ConditionId], [w].[ProductId], [w].[ExtensionId], [w].[PartialPrice]
FROM [WarrantyProducts] AS [w]
INNER JOIN [WarrantyCondition] AS [w0] ON ([w].[ConditionWarrantyId] = [w0].[WarrantyId]) AND ([w].[ConditionId] = [w0].[Id])
INNER JOIN [Warranties] AS [w1] ON [w0].[WarrantyId] = [w1].[Id]
WHERE [w1].[Id] = 1
```

Even though all the primary keys are already stored in the WarrantyProducts table, so the two joins should not be needed.

Ok, I could just query on the exposed keys instead of navigation properties, but I was trying to auto-generate the foreign primary keys as shadow properties only, and I came across this result which invalidates performance.

Would it be too complicated to extract the conditions and check if they only consist of foreign keys?

Here's what I was trying to do: auto-generated foreign primary keys

This is what I had in mind, and it works, I think this would greatly consolidate EF as it would avoid repeating foreign keys

```C#
public class Warranty {
// Primary key in Fluent API
public int Id { get; set; }

// DATA
[...]

// Navigation
public ICollection? Conditions { get; set; }
}

public class WarrantyCondition {
// Composite key in Fluent API (recursively retrieves keys from the navigations)
public Warranty? Warranty{ get; set; }
public int Id { get; set; }

// DATA
[...]

// Navigation
public ICollection? Products { get; set; }
}

public class WarrantyProduct {
// Composite key in Fluent API (recursively retrieves keys from the navigations)
public WarrantyCondition? Condition { get; set; }
public Product? Product { get; set; }

// DATA
[...]
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.