在Linq查询中调用方法

我想在我的表中插入一个名为“S”的列,它将根据从表列获取的值获取一些字符串值。

例如: for each ID (az)我想得到它的字符串值存储在另一个表中。 字符串值从另一个通过Linq查询获取它的方法返回。

  • 是否可以从Linq调用方法?
  • 我应该在同一个查询中做所有事情吗?

这是我需要获得的信息的结构:

az是表#1中第一个方块中的ID,从这个ID我得到表#2中的另一个id,从中我可以得到我需要在列’S’下显示的字符串值。
在此处输入图像描述

 var q = (from a in vA join b in vB on ai equals bj where ak == "aaa" && ah == 0 select new {T = ai, S = someMethod(az).ToString()}) return q; 

S = someMethod(az).ToString()导致以下错误:

无法将类型为“System.Data.Linq.SqlClient.SqlColumn”的对象强制转换为“System.Data.Linq.SqlClient.SqlMethodCall”。

您必须在Linq-to-Objects上下文中执行方法调用,因为在数据库端,方法调用没有意义 – 您可以使用AsEnumerable()来执行此操作 – 基本上,查询的其余部分将被评估为in使用Linq-to-Objects内存收集,您可以按预期使用方法调用:

 var q = (from a in vA join b in vB on ai equals bj where ak == "aaa" && ah == 0 select new {T = ai, Z = az }) .AsEnumerable() .Select(x => new { T = xT, S = someMethod(xZ).ToString() }) 

您需要将其拆分为两个语句。 返回查询中的结果(这将触及数据库),然后在单独的步骤中第二次枚举结果,以将转换转换为新的对象列表。 第二个“查询”不会访问数据库,因此您可以在其中使用someMethod()

Linq-to-Entities有点奇怪,因为它使从C#查询数据库的过渡非常无缝:但你总是要提醒自己,“这个C#将被翻译成一些SQL。” 结果,你必须问自己,“所有这些C#实际上都可以作为SQL执行吗?” 如果它不能 – 如果你在其中调用someMethod() – 你的查询将遇到问题。 通常的解决方案是拆分它。

(@BrokenGlass的另一个答案,使用.AsEnumerable() ,基本上是另一种方法。)

这是一个老问题,但我看不到任何人提到一个“黑客”,它允许在选择期间调用方法而不重复。 想法是使用构造函数,在构造函数中你可以调用你想要的任何东西(至少它在LINQ中使用NHibernate工作正常,不确定LINQ2SQL或EF,但我想它应该是相同的)。 下面我有基准程序的源代码,看起来重复方法在我的情况下比构造函数方法慢两倍,我想毫无疑问 – 我的业务逻辑很小,所以迭代和内存分配等问题很重要。

我还希望有更好的方式来说,不应该尝试在数据库上执行这个或那个,

 // Here are the results of selecting sum of 1 million ints on my machine: // Name Iterations Percent // reiterate 294 53.3575317604356% // constructor 551 100% public class A { public A() { } public A(int b, int c) { Result = Sum(b, c); } public int Result { get; set; } public static int Sum(int source1, int source2) { return source1 + source2; } } class Program { static void Main(string[] args) { var range = Enumerable.Range(1, 1000000).ToList(); BenchmarkIt.Benchmark.This("reiterate", () => { var tst = range .Select(x => new { b = x, c = x }) .AsEnumerable() .Select(x => new A { Result = A.Sum(xb, xc) }) .ToList(); }) .Against.This("constructor", () => { var tst = range .Select(x => new A(x, x)) .ToList(); }) .For(60) .Seconds() .PrintComparison(); Console.ReadKey(); } }