dotnet / dotnet/efcore

Better exception for incomplete inline instantiation of types

Open
#32,988 2 comments 0 reactions 0 assignees View on GitHub
area-query
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

Our complex type support (#31460) allows comparing complex types directly:

```c#
_ = await ctx.Foos.Where(f => f.Address == new Address { Street = f.Name, City = "a" }).ToListAsync();
```

```sql
SELECT [f].[Id], [f].[Name], [f].[Address_City], [f].[Address_Street], [f].[OwnedAddress_City], [f].[OwnedAddress_Street]
FROM [Foos] AS [f]
WHERE [f].[Address_City] = N'a' AND [f].[Address_Street] = [f].[Name]
```

However, if one of the properties is omitted in the inline complex type, translation fails:

```c#
_ = await ctx.Foos.Where(f => f.Address == new Address { Street = f.Name }).ToListAsync();
```

```
Unhandled exception. System.InvalidOperationException: Translation of 'EF.Property(new Address{ Street = StructuralTypeShaperExpression:
Foo
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
.Name }
, "City")' failed. Either the query source is not an entity type, or the specified property does not exist on the entity type.
```

It's not immediately clear what should happen here - the CLR default could be used, or we could not generate a comparison for the absent property altogether (though that seems against the LINQ meaning). It may be better to let this throw, requiring all properties to be listed out - but at the very least it would be better to have a clearer exception saying this.

Full repro

```c#
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();

_ = await ctx.Foos.Where(f => f.Address == new Address { Street = f.Name }).ToListAsync();

public class BlogContext : DbContext
{
public DbSet Foos { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity().ComplexProperty(f => f.Address);
}
}

public class Foo
{
public int Id { get; set; }
public string Name { get; set; }

public Address Address { get; set; }
public Address2 OwnedAddress { get; set; }
}

public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
```

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.