我想在我的表中插入一个名为“S”的列,它将根据从表列中获取的值获得一些字符串值。
例如:for each ID (a.z)
我想让它的字符串值存储在另一个表中。字符串值从另一个通过Linq查询获取它的方法返回。
这是我需要获得的信息的结构:
az是表#1中第一个方块中的ID,从这个ID我得到表#2中的另一个id,从中我可以得到我需要在'S'列下显示的字符串值。 />
var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, S = someMethod(a.z).ToString()})
return q;
导致以下错误的行S = someMethod(a.z).ToString()
:
无法转换'System.Data.Linq.SqlClient.SqlColumn'类型的对象 输入'System.Data.Linq.SqlClient.SqlMethodCall'。
答案 0 :(得分:52)
您必须在Linq-to-Objects
上下文中执行方法调用,因为在数据库端方法调用没有意义 - 您可以使用AsEnumerable()
执行此操作 - 基本上其余的查询将会使用Linq-to-Objects
评估为内存集合,您可以按预期使用方法调用:
var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, Z = a.z })
.AsEnumerable()
.Select(x => new { T = x.T, S = someMethod(x.Z).ToString() })
答案 1 :(得分:10)
您需要将其拆分为两个语句。返回查询中的结果(这将是命中数据库的结果),然后在单独的步骤中第二次枚举结果,以将转换转换为新的对象列表。第二个“查询”不会访问数据库,因此您可以使用其中的someMethod()
。
Linq-to-Entities有点奇怪,因为它使从C#查询数据库的过渡非常无缝:但你总是要提醒自己,“这个C#将被翻译成一些SQL。 “结果,你必须问自己,“所有这些C#实际上都可以作为SQL执行吗?”如果它不能 - 如果你在其中调用someMethod()
- 你的查询将遇到问题。通常的解决方案是拆分它。
(来自@BrokenGlass的另一个答案,使用.AsEnumerable()
,基本上是另一种方法。)
答案 2 :(得分:0)
这是一个老问题,但是我没有提到一个" hack",它允许在select期间调用方法而不重复。想法是使用构造函数,在构造函数中你可以调用你想要的任何东西(至少它在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(x.b, x.c)
})
.ToList();
})
.Against.This("constructor", () =>
{
var tst = range
.Select(x => new A(x, x))
.ToList();
})
.For(60)
.Seconds()
.PrintComparison();
Console.ReadKey();
}
}