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

Query: Where() on derived property fails with undefined property on base class exception #7499

Closed
rmja opened this issue Jan 27, 2017 · 5 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@rmja
Copy link

rmja commented Jan 27, 2017

Consider the following model:

public class Message
{
        public int Id { get; private set; }

        public MessageSender Sender { get; private set; }

        public ICollection<MessageRecipient> Recipients { get; private set; }
}

MessageSender and MessageRecipient are abstract classes that have different implementation depending on their kind.

To get the "inbox" I can issue the following query:

db.Messages.Where(message =>
                message.Recipients.OfType<UserMessageRecipient>().Any(x => x.UserId == userId) ||
                message.Recipients.OfType<EmailMessageRecipient>().Any(x => x.Email == email))

However, to get the "outbox" where the query is run on the Sender property, I cannot

db.Messages.Where(message =>
                (message.Sender is UserMessageSender && ((UserMessageSender)message.Sender).UserId == userId) ||
                (message.Sender is EmailMessageSender && ((EmailMessageSender )message.Sender).Email == email))

The following exception is thrown:

Exception thrown: 'System.ArgumentException' in mscorlib.dll

Additional information: Property 'System.String UserId' is not defined for type 'Messaging.Models.MessageSender'

   at System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.<>c__DisplayClass20_0.<VisitMember>b__2(Expression e)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.RewriteNavigationsIntoJoins(QuerySourceReferenceExpression outerQuerySourceReferenceExpression, IEnumerable`1 navigations, Type propertyType, Func`2 propertyCreator, Func`2 conditionalAccessPropertyCreator)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.<>c__DisplayClass20_0.<VisitMember>b__0(IEnumerable`1 ps, IQuerySource qs)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.BindPropertyExpressionCore[TResult](Expression propertyExpression, IQuerySource querySource, Func`3 propertyBinder)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.BindNavigationPathPropertyExpression[TResult](Expression propertyExpression, Func`3 propertyBinder)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitMember(MemberExpression node)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitBinary(BinaryExpression node)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitConditional(ConditionalExpression node)
   at Remotion.Linq.Clauses.WhereClause.TransformExpressions(Func`2 transformation)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.Rewrite(QueryModel queryModel, QueryModel parentQueryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.OptimizeQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__129`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToArrayAsync>d__130`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

Further technical details

EF Core version: 1.1.0
Database Provider: SqlServer
Operating system: Windows 10
IDE: Visual Studio 2015

@smitpatel
Copy link
Contributor

Navigation rewrite ignores the conversion applied onto navigation. Sample test is in https://github.com/aspnet/EntityFramework/tree/propertyonderivedtype7499

Passing to @maumar

@smitpatel smitpatel assigned maumar and unassigned smitpatel Feb 16, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Apr 19, 2017
@maumar
Copy link
Contributor

maumar commented Apr 22, 2017

working on a fix now

maumar added a commit that referenced this issue Apr 27, 2017
…rty on base class exception

Problem was that we were not taking type differences and expression converts in various places during compilation. We sometimes remove converts when processing expressions, but then not accounting for them when we re-assemble the visited expression.
This caused many scenarios involving casts (e.g. accessing properties/navigations on derived types) to fail.

Fix is to start compensating for those where necessary. Created helper methods for EF.Property method call, member access and assignment and using them instead of regular Expression APIs.

Also fixed unrelated issue in the SqlTranslatingExpressionVisitor - when trying to translate MethodCall expression, we would force client evaluation, if arguments to the function was a subquery - this is not ideal, since we can translate some of the subqueries (ones that return single result).
maumar added a commit that referenced this issue Apr 27, 2017
…rty on base class exception

Problem was that we were not taking type differences and expression converts in various places during compilation. We sometimes remove converts when processing expressions, but then not accounting for them when we re-assemble the visited expression.
This caused many scenarios involving casts (e.g. accessing properties/navigations on derived types) to fail.

Fix is to start compensating for those where necessary. Created helper methods for EF.Property method call, member access and assignment and using them instead of regular Expression APIs.

Also fixed unrelated issue in the SqlTranslatingExpressionVisitor - when trying to translate MethodCall expression, we would force client evaluation, if arguments to the function was a subquery - this is not ideal, since we can translate some of the subqueries (ones that return single result).
maumar added a commit that referenced this issue Apr 28, 2017
…rty on base class exception

Problem was that we were not taking type differences and expression converts in various places during compilation. We sometimes remove converts when processing expressions, but then not accounting for them when we re-assemble the visited expression.
This caused many scenarios involving casts (e.g. accessing properties/navigations on derived types) to fail.

Fix is to start compensating for those where necessary. Created helper methods for EF.Property method call, member access and assignment and using them instead of regular Expression APIs.

Also fixed unrelated issue in the SqlTranslatingExpressionVisitor - when trying to translate MethodCall expression, we would force client evaluation, if arguments to the function was a subquery - this is not ideal, since we can translate some of the subqueries (ones that return single result).
maumar added a commit that referenced this issue Apr 28, 2017
…rty on base class exception

Problem was that we were not taking type differences and expression converts in various places during compilation. We sometimes remove converts when processing expressions, but then not accounting for them when we re-assemble the visited expression.
This caused many scenarios involving casts (e.g. accessing properties/navigations on derived types) to fail.

Fix is to start compensating for those where necessary. Created helper methods for EF.Property method call, member access and assignment and using them instead of regular Expression APIs.

Also fixed unrelated issue in the SqlTranslatingExpressionVisitor - when trying to translate MethodCall expression, we would force client evaluation, if arguments to the function was a subquery - this is not ideal, since we can translate some of the subqueries (ones that return single result).
@maumar
Copy link
Contributor

maumar commented Apr 28, 2017

fixed in c6a0602

@maumar maumar closed this as completed Apr 28, 2017
@maumar maumar added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Apr 28, 2017
@maumar maumar modified the milestones: 2.0.0-preview1, 2.0.0 Apr 28, 2017
@smitpatel
Copy link
Contributor

@maumar - Please file a bug for clean up too.

@SebaVDPInfra
Copy link

We found a workaround for this issue.
We used "as" instead of casting and it worked fine.

b.Messages.Where(message => (message.Sender is UserMessageSender && (message.Sender as UserMessageSender).UserId == userId) || (message.Sender is EmailMessageSender && (message.Sender as EmailMessageSender).Email == email))

@ajcvickers ajcvickers changed the title Where() on derived property fails with undefined property on base class exception Query: Where() on derived property fails with undefined property on base class exception May 9, 2017
@divega divega added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. labels May 10, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

7 participants