为什么 LINQ-to-SQL 有时允许我使用函数进行投影,但有时却不允许?
Why does LINQ-to-SQL sometimes allow me to project using a function, but sometimes it does not?
这真是让我百思不得其解。我知道 LINQ-to-SQL 通过处理表达式树并尝试通过生成的查询来翻译内容来处理选择,这就是为什么某些函数翻译不起作用 属性(string.IsNullOrWhitespace
是经常的烦恼)。
我在我的代码中遇到了 LINQ-to-SQL 能够通过 Select 投影调用我的辅助函数的情况......有时。事实上,当方法有一个名称时它会起作用,但如果它有另一个名称则不起作用。我认为下面的程序最好地说明了这一点(这是我能做到的最简单的):
// #define BREAK_THE_CODE
using System;
using Sandbox.Data;
using System.Collections.Generic;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
List<MyValue> myValueList;
try
{
myValueList = dataContext.Numbers.Select(x => new MyValue
{
#if BREAK_THE_CODE
Type = ToValueType(x.Value),
#else
Type = DoIt(x.Value),
#endif
}).ToList();
}
catch (NotSupportedException)
{
System.Console.WriteLine("Not supported, oh noes!");
System.Console.ReadKey();
return;
}
System.Console.WriteLine(myValueList.Count);
System.Console.ReadKey();
}
}
#if BREAK_THE_CODE
public static MyValueType ToValueType(int value)
#else
public static MyValueType DoIt(int value)
#endif
{
return MyValueType.One;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
One,
Two,
Unknown,
}
}
}
后备数据库只有一个名为 [Number]
的 table,只有一个列 [Value] INT NOT NULL
。
正如所写,该程序对我有用,但取消注释顶部的 #define
将切换方法调用的名称,然后程序将在执行 [=18] 时抛出 NotSupportedException
=].
我已经尝试了几种不同的方法名称来尝试确定一种模式,但一直无法确定。看起来如果方法被命名为以 To
它会抛出 NotSupportedException
,但似乎可以使用任何其他名称。这还是很奇怪。
有人可以解释发生了什么吗?
这是另一个没有 #define
切换的示例,它只是背靠背地执行两种方法,我仍然看到同样的问题。具体来说,DoIt
有效,但 ToValueType
无效。
using System;
using Sandbox.Data;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = DoIt(x.Value),
}).ToList();
System.Console.WriteLine("DoIt Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("DoIt Failed, oh noes!");
}
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = ToValueType(x.Value),
}).ToList();
System.Console.WriteLine("ToValueType Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("ToValueType Failed, oh noes!");
}
System.Console.ReadKey();
}
}
public static MyValueType DoIt(int value)
{
return MyValueType.SpecialType;
}
public static MyValueType ToValueType(int value)
{
return MyValueType.SpecialType;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
SpecialType,
}
}
}
这是一个 L2S 错误。这有望奏效。
我在反编译后的源码中发现:
private static MethodSupport GetDecimalMethodSupport(SqlMethodCall mc)
{
if (mc.Method.IsStatic)
{
if (mc.Arguments.Count == 2)
{
string str;
if (((str = mc.Method.Name) != null) && ((((str == "Multiply") || (str == "Divide")) || ((str == "Subtract") || (str == "Add"))) || ((str == "Remainder") || (str == "Round"))))
{
return MethodSupport.Method;
}
}
else if (mc.Arguments.Count == 1)
{
string str2;
if (((str2 = mc.Method.Name) != null) && (((str2 == "Negate") || (str2 == "Floor")) || ((str2 == "Truncate") || (str2 == "Round"))))
{
return MethodSupport.Method;
}
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
{
return MethodSupport.Method;
}
}
}
return MethodSupport.None;
}
正在搜索 "To"
:
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
嗯...还有一个地方。也许 L2S 认为您的值类型是小数。尝试添加第二个参数来打破 mc.Arguments.Count == 1
条件。
无论如何,这是一个错误。这背后没有更深层次的原因。通常情况下,L2S 可以执行最终 Select 中的函数就好了。这是 EF 仍然缺乏的一个很棒的功能。
暂时搁置并尽快迁移到 EF。 L2S被放弃。
这真是让我百思不得其解。我知道 LINQ-to-SQL 通过处理表达式树并尝试通过生成的查询来翻译内容来处理选择,这就是为什么某些函数翻译不起作用 属性(string.IsNullOrWhitespace
是经常的烦恼)。
我在我的代码中遇到了 LINQ-to-SQL 能够通过 Select 投影调用我的辅助函数的情况......有时。事实上,当方法有一个名称时它会起作用,但如果它有另一个名称则不起作用。我认为下面的程序最好地说明了这一点(这是我能做到的最简单的):
// #define BREAK_THE_CODE
using System;
using Sandbox.Data;
using System.Collections.Generic;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
List<MyValue> myValueList;
try
{
myValueList = dataContext.Numbers.Select(x => new MyValue
{
#if BREAK_THE_CODE
Type = ToValueType(x.Value),
#else
Type = DoIt(x.Value),
#endif
}).ToList();
}
catch (NotSupportedException)
{
System.Console.WriteLine("Not supported, oh noes!");
System.Console.ReadKey();
return;
}
System.Console.WriteLine(myValueList.Count);
System.Console.ReadKey();
}
}
#if BREAK_THE_CODE
public static MyValueType ToValueType(int value)
#else
public static MyValueType DoIt(int value)
#endif
{
return MyValueType.One;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
One,
Two,
Unknown,
}
}
}
后备数据库只有一个名为 [Number]
的 table,只有一个列 [Value] INT NOT NULL
。
正如所写,该程序对我有用,但取消注释顶部的 #define
将切换方法调用的名称,然后程序将在执行 [=18] 时抛出 NotSupportedException
=].
我已经尝试了几种不同的方法名称来尝试确定一种模式,但一直无法确定。看起来如果方法被命名为以 To
它会抛出 NotSupportedException
,但似乎可以使用任何其他名称。这还是很奇怪。
有人可以解释发生了什么吗?
这是另一个没有 #define
切换的示例,它只是背靠背地执行两种方法,我仍然看到同样的问题。具体来说,DoIt
有效,但 ToValueType
无效。
using System;
using Sandbox.Data;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = DoIt(x.Value),
}).ToList();
System.Console.WriteLine("DoIt Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("DoIt Failed, oh noes!");
}
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = ToValueType(x.Value),
}).ToList();
System.Console.WriteLine("ToValueType Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("ToValueType Failed, oh noes!");
}
System.Console.ReadKey();
}
}
public static MyValueType DoIt(int value)
{
return MyValueType.SpecialType;
}
public static MyValueType ToValueType(int value)
{
return MyValueType.SpecialType;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
SpecialType,
}
}
}
这是一个 L2S 错误。这有望奏效。
我在反编译后的源码中发现:
private static MethodSupport GetDecimalMethodSupport(SqlMethodCall mc)
{
if (mc.Method.IsStatic)
{
if (mc.Arguments.Count == 2)
{
string str;
if (((str = mc.Method.Name) != null) && ((((str == "Multiply") || (str == "Divide")) || ((str == "Subtract") || (str == "Add"))) || ((str == "Remainder") || (str == "Round"))))
{
return MethodSupport.Method;
}
}
else if (mc.Arguments.Count == 1)
{
string str2;
if (((str2 = mc.Method.Name) != null) && (((str2 == "Negate") || (str2 == "Floor")) || ((str2 == "Truncate") || (str2 == "Round"))))
{
return MethodSupport.Method;
}
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
{
return MethodSupport.Method;
}
}
}
return MethodSupport.None;
}
正在搜索 "To"
:
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
嗯...还有一个地方。也许 L2S 认为您的值类型是小数。尝试添加第二个参数来打破 mc.Arguments.Count == 1
条件。
无论如何,这是一个错误。这背后没有更深层次的原因。通常情况下,L2S 可以执行最终 Select 中的函数就好了。这是 EF 仍然缺乏的一个很棒的功能。
暂时搁置并尽快迁移到 EF。 L2S被放弃。