From eaea67d050b62295cb39c2b5cfc9430faf30f9ad Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 17 May 2020 16:20:39 +0200 Subject: [PATCH 1/2] Fix OData filtering by a base class member --- src/NHibernate.Test/Async/Linq/ODataTests.cs | 24 ++++++++++++++++++++ src/NHibernate.Test/Linq/ODataTests.cs | 24 ++++++++++++++++++++ src/NHibernate/Linq/NhLinqExpression.cs | 3 +++ 3 files changed, 51 insertions(+) diff --git a/src/NHibernate.Test/Async/Linq/ODataTests.cs b/src/NHibernate.Test/Async/Linq/ODataTests.cs index 0f794fdae88..44135195c13 100644 --- a/src/NHibernate.Test/Async/Linq/ODataTests.cs +++ b/src/NHibernate.Test/Async/Linq/ODataTests.cs @@ -65,6 +65,28 @@ public async Task OrderGroupByAsync(string queryString, int expectedRows) Assert.That(results, Has.Count.EqualTo(expectedRows)); } + private class CustomerVm : BaseCustomerVm + { + } + + private class BaseCustomerVm + { + public string Id { get; set; } + + public string Name { get; set; } + } + + [TestCase("$filter=Name eq 'Maria Anders'", 1)] + public async Task BasePropertyFilterAsync(string queryString, int expectedRows) + { + var query = ApplyFilter( + session.Query().Select(o => new CustomerVm {Name = o.ContactName, Id = o.CustomerId}), + queryString); + + var results = await (((IQueryable) query).ToListAsync()); + Assert.That(results, Has.Count.EqualTo(expectedRows)); + } + private IQueryable ApplyFilter(IQueryable query, string queryString) { var context = new ODataQueryContext(CreatEdmModel(), typeof(T), null) { }; @@ -143,6 +165,8 @@ private static IEdmModel CreatEdmModel() employeeModel.EntityType.Property(o => o.Title); employeeModel.EntityType.HasMany(o => o.Orders); + builder.EntitySet(nameof(CustomerVm)); + return builder.GetEdmModel(); } diff --git a/src/NHibernate.Test/Linq/ODataTests.cs b/src/NHibernate.Test/Linq/ODataTests.cs index 7ac2a90cda7..572392110c4 100644 --- a/src/NHibernate.Test/Linq/ODataTests.cs +++ b/src/NHibernate.Test/Linq/ODataTests.cs @@ -53,6 +53,28 @@ public void OrderGroupBy(string queryString, int expectedRows) Assert.That(results, Has.Count.EqualTo(expectedRows)); } + private class CustomerVm : BaseCustomerVm + { + } + + private class BaseCustomerVm + { + public string Id { get; set; } + + public string Name { get; set; } + } + + [TestCase("$filter=Name eq 'Maria Anders'", 1)] + public void BasePropertyFilter(string queryString, int expectedRows) + { + var query = ApplyFilter( + session.Query().Select(o => new CustomerVm {Name = o.ContactName, Id = o.CustomerId}), + queryString); + + var results = ((IQueryable) query).ToList(); + Assert.That(results, Has.Count.EqualTo(expectedRows)); + } + private IQueryable ApplyFilter(IQueryable query, string queryString) { var context = new ODataQueryContext(CreatEdmModel(), typeof(T), null) { }; @@ -131,6 +153,8 @@ private static IEdmModel CreatEdmModel() employeeModel.EntityType.Property(o => o.Title); employeeModel.EntityType.HasMany(o => o.Orders); + builder.EntitySet(nameof(CustomerVm)); + return builder.GetEdmModel(); } diff --git a/src/NHibernate/Linq/NhLinqExpression.cs b/src/NHibernate/Linq/NhLinqExpression.cs index 817bfe459e2..ed071f0b54c 100644 --- a/src/NHibernate/Linq/NhLinqExpression.cs +++ b/src/NHibernate/Linq/NhLinqExpression.cs @@ -87,6 +87,9 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter var requiredHqlParameters = new List(); var queryModel = NhRelinqQueryParser.Parse(_expression); + // Use the modified TransparentIdentifierRemovingExpressionVisitor in order to support expressions that were created + // programmatically and do not mimic what the C# compiler generates. + queryModel.TransformExpressions(TransparentIdentifierRemovingExpressionVisitor.ReplaceTransparentIdentifiers); var visitorParameters = new VisitorParameters(sessionFactory, _constantToParameterMap, requiredHqlParameters, new QuerySourceNamer(), TargetType, QueryMode); From 19a4d402b79022b37996b7158f28d6c7f850c6df Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 17 May 2020 17:45:35 +0200 Subject: [PATCH 2/2] Move comment --- src/NHibernate/Linq/NhLinqExpression.cs | 2 -- .../Visitors/TransparentIdentifierRemovingExpressionVisitor.cs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Linq/NhLinqExpression.cs b/src/NHibernate/Linq/NhLinqExpression.cs index ed071f0b54c..ad39397fd71 100644 --- a/src/NHibernate/Linq/NhLinqExpression.cs +++ b/src/NHibernate/Linq/NhLinqExpression.cs @@ -87,8 +87,6 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter var requiredHqlParameters = new List(); var queryModel = NhRelinqQueryParser.Parse(_expression); - // Use the modified TransparentIdentifierRemovingExpressionVisitor in order to support expressions that were created - // programmatically and do not mimic what the C# compiler generates. queryModel.TransformExpressions(TransparentIdentifierRemovingExpressionVisitor.ReplaceTransparentIdentifiers); var visitorParameters = new VisitorParameters(sessionFactory, _constantToParameterMap, requiredHqlParameters, new QuerySourceNamer(), TargetType, QueryMode); diff --git a/src/NHibernate/Linq/Visitors/TransparentIdentifierRemovingExpressionVisitor.cs b/src/NHibernate/Linq/Visitors/TransparentIdentifierRemovingExpressionVisitor.cs index a2901b4068d..7016438e321 100644 --- a/src/NHibernate/Linq/Visitors/TransparentIdentifierRemovingExpressionVisitor.cs +++ b/src/NHibernate/Linq/Visitors/TransparentIdentifierRemovingExpressionVisitor.cs @@ -29,6 +29,8 @@ namespace NHibernate.Linq.Visitors // Copied from Relinq and added a fallback for comparing two member info by DeclaringType and Name // 6.0 TODO: drop if https://github.com/OData/WebApi/issues/2108 is fixed and add a possible breaking // change requiring to upgrade OData. (See https://github.com/nhibernate/nhibernate-core/pull/2322#discussion_r401215456 ) + // Use this version in order to support expressions that were created programmatically and do not mimic what the C# compiler generates. + // Consider removing this if https://re-motion.atlassian.net/projects/RMLNQ/issues/RMLNQ-121 is fixed and we upgrade ReLinq. /// /// Replaces expression patterns of the form new T { x = 1, y = 2 }.x () or /// new T ( x = 1, y = 2 ).x () to 1 (or 2 if y is accessed instead of x).