Skip to content

Commit 65910dd

Browse files
jogibear9988sdanylivMaceWindu
authoredSep 3, 2020
Fix for linq2db#2468. Improved members mapping. (linq2db#2469)
* test for issue linq2db#2468 * Fix for linq2db#2468. Improved members mapping. * fix NRT warning Co-authored-by: Svyatoslav Danyliv <sdanyliv@gmail.com> Co-authored-by: MaceWindu <MaceWindu@users.noreply.github.com>
1 parent 99088a0 commit 65910dd

File tree

3 files changed

+153
-8
lines changed

3 files changed

+153
-8
lines changed
 

‎Source/LinqToDB/Linq/Builder/ExpressionBuilder.SqlBuilder.cs

+17-4
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ internal Expression ConvertExpression(Expression expression)
429429

430430
var cm = ConvertMethod(expr);
431431
if (cm != null)
432-
return new TransformInfo(ConvertExpression(cm));
432+
//TODO: looks like a mess: ConvertExpression can not work without OptimizeExpression
433+
return new TransformInfo(OptimizeExpression(ConvertExpression(cm)));
433434
break;
434435
}
435436

@@ -446,7 +447,8 @@ internal Expression ConvertExpression(Expression expression)
446447
if (expr.Type != e.Type)
447448
expr = new ChangeTypeExpression(expr, e.Type);
448449

449-
return new TransformInfo(ConvertExpression(expr));
450+
//TODO: looks like a mess: ConvertExpression can not work without OptimizeExpression
451+
return new TransformInfo(OptimizeExpression(ConvertExpression(expr)));
450452
}
451453

452454
if (ma.Member.IsNullableValueMember())
@@ -535,8 +537,19 @@ internal Expression ConvertExpression(Expression expression)
535537

536538
Expression? ConvertMethod(MethodCallExpression pi)
537539
{
538-
var l = Expressions.ConvertMember(MappingSchema, pi.Object?.Type, pi.Method);
539-
return l == null ? null : ConvertMethod(pi, l);
540+
LambdaExpression? lambda = null;
541+
542+
if (!pi.Method.IsStatic && pi.Object != null && pi.Object.Type != pi.Method.DeclaringType)
543+
{
544+
var concreteTypeMemberInfo = pi.Object.Type.GetMemberEx(pi.Method);
545+
if (concreteTypeMemberInfo != null)
546+
lambda = Expressions.ConvertMember(MappingSchema, pi.Object.Type, concreteTypeMemberInfo);
547+
}
548+
549+
if (lambda == null)
550+
lambda = Expressions.ConvertMember(MappingSchema, pi.Object?.Type, pi.Method);
551+
552+
return lambda == null ? null : ConvertMethod(pi, lambda);
540553
}
541554

542555
static Expression ConvertMethod(MethodCallExpression pi, LambdaExpression lambda)

‎Source/LinqToDB/Linq/Expressions.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1574,14 +1574,14 @@ static TypeMember MT<T>(Expression<Func<object>> func)
15741574
{ MT<decimal>(() => ((decimal) 0) .ToString()), N(() => L<decimal, string>((decimal p0) => Sql.ConvertTo<string>.From(p0) )) },
15751575
{ MT<double >(() => ((double) 0) .ToString()), N(() => L<double, string>((double p0) => Sql.ConvertTo<string>.From(p0) )) },
15761576
{ MT<short >(() => ((short) 0) .ToString()), N(() => L<short, string>((short p0) => Sql.ConvertTo<string>.From(p0) )) },
1577-
{ MT<int >(() => ((int) 0) .ToString()), N(() => L<int, string>((int p0) => Sql.ConvertTo<string>.From(p0) )) },
1578-
{ MT<long >(() => ((long) 0) .ToString()), N(() => L<long, string>((long p0) => Sql.ConvertTo<string>.From(p0) )) },
1577+
{ MT<int >(() => ((int) 0) .ToString()), N(() => L<int, string>((int p0) => Sql.ConvertTo<string>.From(p0) )) },
1578+
{ MT<long >(() => ((long) 0) .ToString()), N(() => L<long, string>((long p0) => Sql.ConvertTo<string>.From(p0) )) },
15791579
{ MT<sbyte >(() => ((sbyte) 0) .ToString()), N(() => L<sbyte, string>((sbyte p0) => Sql.ConvertTo<string>.From(p0) )) },
15801580
{ MT<float >(() => ((float) 0) .ToString()), N(() => L<float, string>((float p0) => Sql.ConvertTo<string>.From(p0) )) },
15811581
// { MT<string >(() => ((string) "0") .ToString()), N(() => L<string, string>((string p0) => p0 )) },
15821582
{ MT<ushort >(() => ((ushort) 0) .ToString()), N(() => L<ushort, string>((ushort p0) => Sql.ConvertTo<string>.From(p0) )) },
1583-
{ MT<uint >(() => ((uint) 0) .ToString()), N(() => L<uint, string>((uint p0) => Sql.ConvertTo<string>.From(p0) )) },
1584-
{ MT<ulong >(() => ((ulong) 0) .ToString()), N(() => L<ulong, string>((ulong p0) => Sql.ConvertTo<string>.From(p0) )) },
1583+
{ MT<uint >(() => ((uint) 0) .ToString()), N(() => L<uint, string>((uint p0) => Sql.ConvertTo<string>.From(p0) )) },
1584+
{ MT<ulong >(() => ((ulong) 0) .ToString()), N(() => L<ulong, string>((ulong p0) => Sql.ConvertTo<string>.From(p0) )) },
15851585

15861586
#endregion
15871587

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using System;
2+
using System.Linq;
3+
using System.Linq.Expressions;
4+
using LinqToDB;
5+
using LinqToDB.Data;
6+
using LinqToDB.Linq;
7+
using LinqToDB.Mapping;
8+
using NUnit.Framework;
9+
10+
namespace Tests.UserTests
11+
{
12+
[TestFixture]
13+
public class Issue2468Tests : TestBase
14+
{
15+
public enum StatusEnum
16+
{
17+
Unknown = 0,
18+
Open = 1,
19+
InProgress = 2,
20+
Done = 3,
21+
}
22+
23+
public enum ColorEnum
24+
{
25+
Blue = 0,
26+
Red = 10,
27+
Green = 20,
28+
}
29+
30+
public enum CMYKEnum
31+
{
32+
Cyan = 0,
33+
Magenta = 10,
34+
Yellow = 20,
35+
Black = 40,
36+
}
37+
38+
[Table]
39+
public class InventoryResourceDTO
40+
{
41+
[Column]
42+
public Guid Id { get; set; }
43+
44+
[Column]
45+
public StatusEnum Status { get; set; }
46+
47+
[Column]
48+
public ColorEnum Color { get; set; }
49+
50+
[Column]
51+
public CMYKEnum CMYKColor { get; set; }
52+
}
53+
54+
private static class MyExtensions
55+
{
56+
[ExpressionMethod(nameof(StatusEnumToStringImpl))]
57+
public static string StatusEnumToString(StatusEnum v)
58+
{
59+
return v.ToString();
60+
}
61+
62+
private static Expression<Func<StatusEnum, string>> StatusEnumToStringImpl()
63+
{
64+
return v => v == StatusEnum.Done ? "Done" :
65+
v == StatusEnum.Open ? "Open" :
66+
v == StatusEnum.InProgress ? "InProgress" : "Unknown";
67+
}
68+
}
69+
70+
public static void MapEnumToString<T>() where T : struct
71+
{
72+
MapEnumToString(typeof(T));
73+
}
74+
75+
public static void MapEnumToString(Type type)
76+
{
77+
var param = Expression.Parameter(type, "enum");
78+
var values = Enum.GetValues(type);
79+
var list = (System.Collections.IList)values;
80+
Expression retE = Expression.Constant(null, typeof(string));
81+
82+
for (var i = values.Length - 1; i >= 0; i--)
83+
{
84+
var v = list[i]!;
85+
var eq = Expression.Equal(Expression.Constant(v, type), param);
86+
retE = Expression.Condition(eq, Expression.Constant(v.ToString()), retE);
87+
}
88+
89+
var lambda = Expression.Lambda(retE, param);
90+
91+
var toStringMethod = type.GetMethods().First(m => m.Name == "ToString" && m.GetParameters().Length == 0);
92+
93+
Expressions.MapMember(toStringMethod, lambda);
94+
}
95+
96+
97+
static Issue2468Tests()
98+
{
99+
MapEnumToString<ColorEnum>();
100+
MapEnumToString<CMYKEnum>();
101+
Expressions.MapMember((StatusEnum v) => v.ToString(), v => MyExtensions.StatusEnumToString(v));
102+
}
103+
104+
[Test]
105+
public void Issue2468Test(
106+
[IncludeDataSources(TestProvName.AllSQLite)]
107+
string context)
108+
{
109+
110+
using (var db = (DataConnection)GetDataContext(context))
111+
using (var itb = db.CreateLocalTable<InventoryResourceDTO>())
112+
{
113+
var dto1 = new InventoryResourceDTO
114+
{
115+
Color = ColorEnum.Blue, Id = Guid.NewGuid(), CMYKColor = CMYKEnum.Cyan, Status = StatusEnum.Open
116+
};
117+
118+
db.Insert(dto1);
119+
120+
var list = itb
121+
.Where(x =>
122+
x.Color.ToString().Contains("Bl")
123+
&& x.CMYKColor.ToString().Contains("Cya")
124+
&& x.Status.ToString().Contains("en")
125+
)
126+
.ToList();
127+
128+
Assert.That(list.Count, Is.EqualTo(1));
129+
}
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)
Please sign in to comment.