dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.68k stars 3.17k forks source link

Complex types throw for SQL Server views #33592

Closed attilavlacsil closed 2 months ago

attilavlacsil commented 5 months ago

Summary

I'm trying to use complex types as described in What's New in EF Core 8 and it works fine for tables, but I get the following exception when I try to use the same setup with SQL Server views:

Unhandled exception. System.InvalidOperationException: Sequence contains no elements
   at System.Linq.ThrowHelper.ThrowNoElementsException()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.GenerateComplexPropertyShaperExpression(StructuralTypeProjectionExpression containerProjection, IComplexProperty complexProperty)
   at Microsoft.EntityFrameworkCore.Query.StructuralTypeProjectionExpression.BindComplexProperty(IComplexProperty complexProperty)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.<ApplyProjection>g__ProcessType|65_19(StructuralTypeProjectionExpression typeProjection, <>c__DisplayClass65_6&)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.<ApplyProjection>g__AddStructuralTypeProjection|65_0(StructuralTypeProjectionExpression projection)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ApplyProjection(Expression shaperExpression, ResultCardinality resultCardinality, QuerySplittingBehavior querySplittingBehavior)
   at Microsoft.EntityFrameworkCore.Query.Internal.SelectExpressionProjectionApplyingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPostprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerQueryTranslationPostprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IAsyncEnumerable<TEntity>.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in C:\work\EfCoreSamples\EfCoreComplexTypes\Program.cs:line 20
   at Program.<Main>(String[] args)

Reproduction steps

To reproduce the issue, simply create a view for the (generated) database setup, and configure the model with ToView instead of ToTable.

CREATE VIEW [dbo].[CustomerView]
AS
SELECT [Id]
      ,[Name]
      ,[Address_City]
      ,[Address_Country]
      ,[Address_Line1]
      ,[Address_Line2]
      ,[Address_PostCode]
FROM [dbo].[Customer]
public readonly record struct Address(string Line1, string? Line2, string City, string Country, string PostCode);

public class Customer
{
    public int Id { get; set; }
    public required string Name { get; set; }
    public required Address Address { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Customer>(e =>
    {
        e.ToView("CustomerView");

        e.HasKey(x => x.Id);
        e.ComplexProperty(x => x.Address);
    });
}

Full code sample: Program.cs.txt

Expected behavior

I expect EF generates a similar query as for tables:

SELECT [c].[Id], [c].[Name], [c].[Address_City], [c].[Address_Country], [c].[Address_Line1], [c].[Address_Line2], [c].[Address_PostCode]
FROM [CustomerView] AS [c]

Provider and version information

EF Core version: 8.0.4 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 8.0 Operating system: Windows 11 IDE: Visual Studio 2022 17.9.6

ajcvickers commented 5 months ago

Possible duplicate of #33129