From 708a66c9c57fcb3bebd2f53d8a95de26f35c685a Mon Sep 17 00:00:00 2001 From: Aleksey Martynov Date: Tue, 5 Mar 2019 16:07:13 +0300 Subject: [PATCH 1/3] Preparatory refactoring --- .../FilterExpressionCompiler.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs b/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs index babfffaf..97eb26bb 100644 --- a/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs +++ b/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs @@ -92,11 +92,20 @@ Expression CompileBinary(ParameterExpression dataItemExpr, IList criteriaJson) { if(accessorExpr.Type == typeof(String) && IsInequality(expressionType)) { var compareMethod = typeof(String).GetMethod(nameof(String.Compare), new[] { typeof(String), typeof(String) }); - accessorExpr = Expression.Call(null, compareMethod, accessorExpr, valueExpr); - valueExpr = Expression.Constant(0); - } else if(useDynamicBinding) { - accessorExpr = Expression.Call(typeof(Utils).GetMethod(nameof(Utils.DynamicCompare)), accessorExpr, valueExpr); - valueExpr = Expression.Constant(0); + return Expression.MakeBinary( + expressionType, + Expression.Call(compareMethod, accessorExpr, valueExpr), + Expression.Constant(0) + ); + } + + if(useDynamicBinding) { + var compareMethod = typeof(Utils).GetMethod(nameof(Utils.DynamicCompare)); + return Expression.MakeBinary( + expressionType, + Expression.Call(compareMethod, accessorExpr, valueExpr), + Expression.Constant(0) + ); } return Expression.MakeBinary(expressionType, accessorExpr, valueExpr); From 221168f1e167be3003a258484f009f20566a9bb5 Mon Sep 17 00:00:00 2001 From: Aleksey Martynov Date: Tue, 5 Mar 2019 17:50:59 +0300 Subject: [PATCH 2/3] The fix --- .../FilterExpressionCompilerTests.cs | 27 ++++++++++++++++++ .../FilterExpressionCompiler.cs | 28 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs b/net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs index e014d1ec..6b0d51a2 100644 --- a/net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs +++ b/net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs @@ -290,6 +290,33 @@ string CompileOperation(string op) { Assert.Equal("False", CompileOperation("<=")); } + [Fact] + public void GuidComparison() { + // https://github.com/DevExpress/DevExtreme.AspNet.Data/issues/339 + + var sampleGuid = Guid.Empty.ToString(); + + Assert.Equal( + $"(obj.CompareTo({sampleGuid}) > 0)", + Compile(new[] { "this", ">", sampleGuid }).Body.ToString() + ); + + Assert.Equal( + $"(obj.Value.CompareTo({sampleGuid}) < 0)", + Compile(new[] { "this", "<", sampleGuid }).Body.ToString() + ); + + Assert.Equal( + $"IIF((obj == null), False, (obj.Value.CompareTo({sampleGuid}) >= 0))", + Compile(new[] { "this", ">=", sampleGuid }, true).Body.ToString() + ); + + Assert.Equal( + "False", + Compile(new[] { "this", "<=", null }).Body.ToString() + ); + } + } } diff --git a/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs b/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs index 97eb26bb..48b5cc0a 100644 --- a/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs +++ b/net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs @@ -88,6 +88,9 @@ Expression CompileBinary(ParameterExpression dataItemExpr, IList criteriaJson) { if(_stringToLower && clientValue is String) clientValue = ((string)clientValue).ToLower(); + if((accessorExpr.Type == typeof(Guid) || accessorExpr.Type == typeof(Guid?)) && IsInequality(expressionType)) + return CompileGuidComparison(accessorExpr, expressionType, clientValue); + Expression valueExpr = Expression.Constant(clientValue, accessorExpr.Type); if(accessorExpr.Type == typeof(String) && IsInequality(expressionType)) { @@ -117,6 +120,31 @@ bool IsInequality(ExpressionType type) { return type == ExpressionType.LessThan || type == ExpressionType.LessThanOrEqual || type == ExpressionType.GreaterThanOrEqual || type == ExpressionType.GreaterThan; } + Expression CompileGuidComparison(Expression accessorExpr, ExpressionType expressionType, object clientValue) { + if(clientValue == null) + return Expression.Constant(false); + + var result = Expression.MakeBinary( + expressionType, + Expression.Call( + Utils.IsNullable(accessorExpr.Type) ? Expression.Property(accessorExpr, "Value") : accessorExpr, + typeof(Guid).GetMethod(nameof(Guid.CompareTo), new[] { typeof(Guid) }), + Expression.Constant(clientValue, typeof(Guid)) + ), + Expression.Constant(0) + ); + + if(GuardNulls) { + return Expression.Condition( + Expression.MakeBinary(ExpressionType.Equal, accessorExpr, Expression.Constant(null)), + Expression.Constant(false), + result + ); + } + + return result; + } + Expression CompileStringFunction(Expression accessorExpr, string clientOperation, string value) { if(_stringToLower && value != null) value = value.ToLower(); From 62fec1c0e93a8c149f4552264d93449c504785e6 Mon Sep 17 00:00:00 2001 From: Aleksey Martynov Date: Wed, 6 Mar 2019 13:14:21 +0300 Subject: [PATCH 3/3] Add func test --- .../Bug339.cs | 38 +++++++++++++++++++ .../UnitOfWorkHelper.cs | 3 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 net/DevExtreme.AspNet.Data.Tests.Xpo/Bug339.cs diff --git a/net/DevExtreme.AspNet.Data.Tests.Xpo/Bug339.cs b/net/DevExtreme.AspNet.Data.Tests.Xpo/Bug339.cs new file mode 100644 index 00000000..c63f0e69 --- /dev/null +++ b/net/DevExtreme.AspNet.Data.Tests.Xpo/Bug339.cs @@ -0,0 +1,38 @@ +using DevExpress.Xpo; +using System; +using Xunit; + +namespace DevExtreme.AspNet.Data.Tests.Xpo { + + public class Bug339 { + + [Persistent(nameof(Bug339) + "_" + nameof(DataItem))] + public class DataItem { + [Key] + public Guid ID { get; set; } + } + + [Fact] + public void Scenario() { + var guid1 = "".PadLeft(32, '1'); + var guid2 = "".PadLeft(32, '2'); + + UnitOfWorkHelper.Exec(uow => { + uow.Save(new DataItem { ID = new Guid(guid1) }); + uow.Save(new DataItem { ID = new Guid(guid2) }); + + uow.CommitChanges(); + + var loadResult = DataSourceLoader.Load(uow.Query(), new SampleLoadOptions { + Filter = new[] { "ID", "<", guid2 }, + RequireTotalCount = true + }); + + Assert.Equal(1, loadResult.totalCount); + }); + + } + + } + +} diff --git a/net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs b/net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs index d7f628ba..49726e70 100644 --- a/net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs +++ b/net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs @@ -21,7 +21,8 @@ public static void Exec(Action action) { dict.GetDataStoreSchema( typeof(DefaultSort.DataItem), typeof(RemoteGroupingStress.DataItem), - typeof(Summary.DataItem) + typeof(Summary.DataItem), + typeof(Bug339.DataItem) ); var provider = XpoDefault.GetConnectionProvider(