dotnet / dotnet/efcore

Required owned entity on a TPH derived type is materialized for an unrelated row

Open
#38,659 1 comment 0 reactions 1 assignee Claimed by @AndriySvyryd View on GitHub
area-owned-entities area-query customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

### Bug description

Using TPH, a derived type has a required `OwnsOne` navigation:

[efcore-tph-required-owned-repro.zip](https://github.com/user-attachments/files/30072042/efcore-tph-required-owned-repro.zip)

```csharp
modelBuilder.Entity(builder =>
{
builder.OwnsOne(x => x.Shape);
builder.Navigation(x => x.Shape).IsRequired();
});
```

The database contains only a `LineOverlay` and no `CircleOverlay` rows. However,
querying the base type still invokes the `Circle` constructor with `null`:

```csharp
await db.Overlays.AsNoTracking().ToListAsync();
```

```text
CircleOverlay rows in database: 0
Circle constructor called: point is null = True, radius = 0
System.ArgumentNullException: Value cannot be null. (Parameter 'point')
```

## Expected

EF materializes the `LineOverlay` without invoking the `Circle` constructor,
because the row discriminator is `LineOverlay`.

## Reproduction

Run the attached project:

```shell
dotnet run
```

Reproduced with:

- EF Core / SQLite provider 10.0.10
- .NET 10.0

This appears related to #31353, which was fixed in 8.0.3. Unlike that issue,
this owned navigation is explicitly configured as required. Making it optional
avoids the exception, but changes the model semantics: every `CircleOverlay`
must have a `Circle`.

### Your code

```csharp
A complete minimal runnable reproduction project is attached:

[EfCoreTphRequiredOwnedRepro.zip](replace-with-the-link-generated-by-GitHub)

Run it with:

dotnet run
```

### Stack traces

```text
Materializing the base TPH query...
Circle constructor called: point is null = True, radius = 0
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'point')
at System.ArgumentNullException.Throw(String paramName)
at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName)
at Circle..ctor(String point, Double radius) in C:\myfiles\mytemp\projects\efcore-tph-required-owned-repro\Program.cs:line 62
at lambda_method84(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Program.$(String[] args) in C:\myfiles\mytemp\projects\efcore-tph-required-owned-repro\Program.cs:line 32
```

### Verbose output

```text

```

### EF Core version

10.0.10

### Database provider

Microsoft.EntityFrameworkCore.Sqlite

### Target framework

.NET 10

### Operating system

_No response_

### IDE

_No response_

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.