Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Owned collection when owner has composite PK throws translation failure #23130

Closed
lukaszgarstecki opened this issue Oct 29, 2020 · 6 comments · Fixed by #23143
Closed

Owned collection when owner has composite PK throws translation failure #23130

lukaszgarstecki opened this issue Oct 29, 2020 · 6 comments · Fixed by #23143
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Milestone

Comments

@lukaszgarstecki
Copy link

I created a model where I have OwnsMany property used on 2 levels. Code sample below

using Microsoft.EntityFrameworkCore;

namespace EFProjectionRepro
{
    public class Context : DbContext
    {
        public DbSet<Entity> Entities => Set<Entity>();

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer("Server=localhost,1433;User Id=sa;Password=Password1!");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Entity>(cfg =>
            {
                cfg.OwnsMany(e => e.Children, inner =>
                {
                    inner.OwnsMany(e => e.Owned);
                });
            });
        }
    }

    public class Entity
    {
        public int Id { get; set; }
        public List<Child> Children { get; set; }
    }

    public class Child
    {
        public int Id { get; set; }
        public int Type { get; set; }
        public List<Owned> Owned { get; set; }
    }

    public class Owned
    {
        public string Value { get; set; }
    }
}
using Microsoft.EntityFrameworkCore;

namespace EFProjectionRepro
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var dbContext = new Context();

            dbContext.Entities.Add(new Entity());
            await dbContext.SaveChangesAsync();
            await dbContext.Entities.ToListAsync();
        }
    }
}

When running saving Entity works, but when trying to read Entity from sql database (await dbContext.Entities.ToListAsync();) I get exception:

    QueryExpression: 
        Projection Mapping:
            EmptyProjectionMember -> [EntityProjectionExpression]
        SELECT 1
        FROM Owned AS o
    ShaperExpression: EntityShaperExpression: 
            EntityType: Owned
            ValueBufferExpression: 
                ProjectionBindingExpression: EmptyProjectionMember
            IsNullable: False

    .Where(namelessParameter{0} => new object[]
    { 
        (object)EF.Property<int>(EntityShaperExpression: 
            EntityType: Child
            ValueBufferExpression: 
                ProjectionBindingExpression: EmptyProjectionMember
            IsNullable: False
        , "EntityId"), 
        (object)EF.Property<int>(EntityShaperExpression: 
            EntityType: Child
            ValueBufferExpression: 
                ProjectionBindingExpression: EmptyProjectionMember
            IsNullable: False
        , "Id") 
    } != null && new object[]
    { 
        (object)EF.Property<int>(EntityShaperExpression: 
            EntityType: Child
            ValueBufferExpression: 
                ProjectionBindingExpression: EmptyProjectionMember
            IsNullable: False
        , "EntityId"), 
        (object)EF.Property<int>(EntityShaperExpression: 
            EntityType: Child
            ValueBufferExpression: 
                ProjectionBindingExpression: EmptyProjectionMember
            IsNullable: False
        , "Id") 
    } == new object[]
    { 
        (object)EF.Property<int>(namelessParameter{0}, "ChildEntityId"), 
        (object)EF.Property<int>(namelessParameter{0}, "ChildId") 
    })' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0& )
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.TranslateSubquery(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.IncludeExpression.VisitChildren(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.TranslateSubquery(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.IncludeExpression.VisitChildren(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   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 EFProjectionRepro.Program.Main(String[] args) in route/to/file.cs:line 17
   at EFProjectionRepro.Program.<Main>(String[] args)

Switching the model to HasMany for both Child and Owned does not cause exception.

EF Core version: 5.0.0-rc.2.20475.6
Database provider:Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 5.0
Operating system: Ubuntu 18.04
IDE: Visual Studio Code 1.50.1

@smitpatel
Copy link
Member

smitpatel commented Oct 29, 2020

Combination of #20556 #20644

Issue: When OwnsMany parent has a composite PK, translation will fail.
Root Cause: we are still matching for NewExpression for key values check which we converted to NewArrayExpression at some point.

var outerKeyFirstProperty = outerKey is NewExpression newExpression
? ((UnaryExpression)((NewArrayExpression)newExpression.Arguments[0]).Expressions[0]).Operand
: outerKey;

Above needs to do processing like
var predicateBody = Expression.AndAlso(
outerKey is NewArrayExpression newArrayExpression
? newArrayExpression.Expressions
.Select(
e =>
{
var left = (e as UnaryExpression)?.Operand ?? e;
return Expression.NotEqual(left, Expression.Constant(null, left.Type));
})
.Aggregate((l, r) => Expression.AndAlso(l, r))
: Expression.NotEqual(outerKey, Expression.Constant(null, outerKey.Type)),
Expression.Call(_objectEqualsMethodInfo, AddConvertToObject(outerKey), AddConvertToObject(innerKey)));

@ajcvickers
Copy link
Member

@smitpatel Regression?

@smitpatel
Copy link
Member

@ajcvickers - Possible. Many changes affected this area in 5.0. I did not test on 3.1

@smitpatel smitpatel self-assigned this Oct 29, 2020
smitpatel added a commit that referenced this issue Oct 29, 2020
Resolves #23130

Some additional tests changed because it ended up causing client eval in the middle due to another level of OwnsMany
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Oct 29, 2020
@smitpatel
Copy link
Member

@ajcvickers - Confirmed this regression from 3.1 release.

@ajcvickers
Copy link
Member

@smitpatel Let's prepare a fix for Tactics.

@smitpatel
Copy link
Member

@ajcvickers - Done in #23143

@smitpatel smitpatel changed the title Unable to get entity from database with OwnsMany property that has OwnsMany property Owned collection when owner has composite PK throws translation failure Oct 30, 2020
@ajcvickers ajcvickers added this to the 5.0.x milestone Nov 2, 2020
smitpatel added a commit that referenced this issue Nov 2, 2020
@ajcvickers ajcvickers modified the milestones: 5.0.x, 5.0.1 Nov 11, 2020
smitpatel added a commit that referenced this issue Nov 17, 2020
Resolves #23130

Some additional tests changed because it ended up causing client eval in the middle due to another level of OwnsMany
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants