【问题标题】:Calling a method inside a Linq query在 Linq 查询中调用方法
【发布时间】:2023-03-03 14:14:02
【问题描述】:

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

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

  • 是否可以从 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”。

【问题讨论】:

  • 您的问题很不清楚(无论如何对我来说)-您指的是哪些表格?这是 Linq to Entities 还是 Linq to Objects?更有意义的属性和表名也可能有所帮助。
  • 抱歉,我是 Linq 新手,Linq to Entities 或 Linq to Objects 是什么意思?
  • 您的错误信息表明您使用 Linq to SQL - 这就是您访问数据库的方式

标签: c# linq linq-to-sql


【解决方案1】:

您必须在 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() })

【讨论】:

  • 很好的答案,谢谢
  • 我只是想确定一下,所以它会迭代 Enumerable 两次,不是吗?首先,在.AsEnumerable() 之前,其次,在.AsEnumerable() 之后?
  • Select() 之前使用AsEnumerable() 是个窍门。我在Where(x=>..) 中使用返回类型方法,并在“where”之前写AsEnumerable() 不会出错。例如。 .AsEnumerable() .Where(x => x.r.Radius > GeneralHelper.getDistanceFromLatLonInMt(x.r.Latitude, x.r.Longitude, _me.Latitude, _me.Longitude))
  • 这不是一个好主意@fthopkins - 这会导致整个表被加载到内存中,而不是在数据库上运行where 子句。
  • 嗯。那你的解决方案是什么?我需要在 where 子句中使用返回类型方法,但不使用 AsEnumerable() 会给出错误
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    这是一个老问题,但我看到没有人提到一个“黑客”,它允许在选择期间调用方法而无需重复。想法是使用构造函数,在构造函数中你可以调用任何你想要的(至少它在 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多