Skip to content

Commit 925d7a8

Browse files
Support comparison operations for Guid (#342)
1 parent 3eb32ba commit 925d7a8

4 files changed

Lines changed: 109 additions & 6 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using DevExpress.Xpo;
2+
using System;
3+
using Xunit;
4+
5+
namespace DevExtreme.AspNet.Data.Tests.Xpo {
6+
7+
public class Bug339 {
8+
9+
[Persistent(nameof(Bug339) + "_" + nameof(DataItem))]
10+
public class DataItem {
11+
[Key]
12+
public Guid ID { get; set; }
13+
}
14+
15+
[Fact]
16+
public void Scenario() {
17+
var guid1 = "".PadLeft(32, '1');
18+
var guid2 = "".PadLeft(32, '2');
19+
20+
UnitOfWorkHelper.Exec(uow => {
21+
uow.Save(new DataItem { ID = new Guid(guid1) });
22+
uow.Save(new DataItem { ID = new Guid(guid2) });
23+
24+
uow.CommitChanges();
25+
26+
var loadResult = DataSourceLoader.Load(uow.Query<DataItem>(), new SampleLoadOptions {
27+
Filter = new[] { "ID", "<", guid2 },
28+
RequireTotalCount = true
29+
});
30+
31+
Assert.Equal(1, loadResult.totalCount);
32+
});
33+
34+
}
35+
36+
}
37+
38+
}

net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public static void Exec(Action<UnitOfWork> action) {
2121
dict.GetDataStoreSchema(
2222
typeof(DefaultSort.DataItem),
2323
typeof(RemoteGroupingStress.DataItem),
24-
typeof(Summary.DataItem)
24+
typeof(Summary.DataItem),
25+
typeof(Bug339.DataItem)
2526
);
2627

2728
var provider = XpoDefault.GetConnectionProvider(

net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,33 @@ string CompileOperation(string op) {
290290
Assert.Equal("False", CompileOperation("<="));
291291
}
292292

293+
[Fact]
294+
public void GuidComparison() {
295+
// https://github.com/DevExpress/DevExtreme.AspNet.Data/issues/339
296+
297+
var sampleGuid = Guid.Empty.ToString();
298+
299+
Assert.Equal(
300+
$"(obj.CompareTo({sampleGuid}) > 0)",
301+
Compile<Guid>(new[] { "this", ">", sampleGuid }).Body.ToString()
302+
);
303+
304+
Assert.Equal(
305+
$"(obj.Value.CompareTo({sampleGuid}) < 0)",
306+
Compile<Guid?>(new[] { "this", "<", sampleGuid }).Body.ToString()
307+
);
308+
309+
Assert.Equal(
310+
$"IIF((obj == null), False, (obj.Value.CompareTo({sampleGuid}) >= 0))",
311+
Compile<Guid?>(new[] { "this", ">=", sampleGuid }, true).Body.ToString()
312+
);
313+
314+
Assert.Equal(
315+
"False",
316+
Compile<Guid?>(new[] { "this", "<=", null }).Body.ToString()
317+
);
318+
}
319+
293320
}
294321

295322
}

net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,27 @@ Expression CompileBinary(ParameterExpression dataItemExpr, IList criteriaJson) {
8888
if(_stringToLower && clientValue is String)
8989
clientValue = ((string)clientValue).ToLower();
9090

91+
if((accessorExpr.Type == typeof(Guid) || accessorExpr.Type == typeof(Guid?)) && IsInequality(expressionType))
92+
return CompileGuidComparison(accessorExpr, expressionType, clientValue);
93+
9194
Expression valueExpr = Expression.Constant(clientValue, accessorExpr.Type);
9295

9396
if(accessorExpr.Type == typeof(String) && IsInequality(expressionType)) {
9497
var compareMethod = typeof(String).GetMethod(nameof(String.Compare), new[] { typeof(String), typeof(String) });
95-
accessorExpr = Expression.Call(null, compareMethod, accessorExpr, valueExpr);
96-
valueExpr = Expression.Constant(0);
97-
} else if(useDynamicBinding) {
98-
accessorExpr = Expression.Call(typeof(Utils).GetMethod(nameof(Utils.DynamicCompare)), accessorExpr, valueExpr);
99-
valueExpr = Expression.Constant(0);
98+
return Expression.MakeBinary(
99+
expressionType,
100+
Expression.Call(compareMethod, accessorExpr, valueExpr),
101+
Expression.Constant(0)
102+
);
103+
}
104+
105+
if(useDynamicBinding) {
106+
var compareMethod = typeof(Utils).GetMethod(nameof(Utils.DynamicCompare));
107+
return Expression.MakeBinary(
108+
expressionType,
109+
Expression.Call(compareMethod, accessorExpr, valueExpr),
110+
Expression.Constant(0)
111+
);
100112
}
101113

102114
return Expression.MakeBinary(expressionType, accessorExpr, valueExpr);
@@ -108,6 +120,31 @@ bool IsInequality(ExpressionType type) {
108120
return type == ExpressionType.LessThan || type == ExpressionType.LessThanOrEqual || type == ExpressionType.GreaterThanOrEqual || type == ExpressionType.GreaterThan;
109121
}
110122

123+
Expression CompileGuidComparison(Expression accessorExpr, ExpressionType expressionType, object clientValue) {
124+
if(clientValue == null)
125+
return Expression.Constant(false);
126+
127+
var result = Expression.MakeBinary(
128+
expressionType,
129+
Expression.Call(
130+
Utils.IsNullable(accessorExpr.Type) ? Expression.Property(accessorExpr, "Value") : accessorExpr,
131+
typeof(Guid).GetMethod(nameof(Guid.CompareTo), new[] { typeof(Guid) }),
132+
Expression.Constant(clientValue, typeof(Guid))
133+
),
134+
Expression.Constant(0)
135+
);
136+
137+
if(GuardNulls) {
138+
return Expression.Condition(
139+
Expression.MakeBinary(ExpressionType.Equal, accessorExpr, Expression.Constant(null)),
140+
Expression.Constant(false),
141+
result
142+
);
143+
}
144+
145+
return result;
146+
}
147+
111148
Expression CompileStringFunction(Expression accessorExpr, string clientOperation, string value) {
112149
if(_stringToLower && value != null)
113150
value = value.ToLower();

0 commit comments

Comments
 (0)