2012-04-02 28 views
24

Tôi muốn chèn vào bảng của tôi một cột có tên 'S' sẽ nhận được một số giá trị chuỗi dựa trên giá trị mà nó nhận được từ cột bảng.Gọi phương thức bên trong truy vấn LINQ

Ví dụ: for each ID (a.z) Tôi muốn nhận giá trị chuỗi của nó được lưu trữ trong một bảng khác. Giá trị chuỗi được trả về từ một phương thức khác nhận được thông qua truy vấn LINQ.

  • Có thể gọi phương thức từ LINQ không?
  • Tôi có nên làm mọi thứ trong cùng một truy vấn không?

Đây là cấu trúc của thông tin mà tôi cần phải nhận được:

a.z is the ID in the first square in table #1, from this ID I get another id in table #2, and from that I can get my string value that I need to display under column 'S'.
enter image description here

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; 

Dòng S = someMethod(a.z).ToString() gây ra lỗi sau:

Unable to cast object of type 'System.Data.Linq.SqlClient.SqlColumn' to type 'System.Data.Linq.SqlClient.SqlMethodCall'.

+0

câu hỏi của bạn là khá rõ ràng (với tôi anyway) - những gì bảng được bạn đề cập đến ? Đây có phải là LINQ to Entities hoặc LINQ to Objects? Tên bảng và thuộc tính có ý nghĩa hơn cũng có thể hữu ích. – BrokenGlass

+0

Xin lỗi, tôi mới làm quen với LINQ, ý bạn là gì với LINQ to Entities hoặc Linq to Objects? – user990635

+0

Thông báo lỗi của bạn cho biết rằng bạn sử dụng LINQ to SQL - đó là cách bạn truy nhập cơ sở dữ liệu – BrokenGlass

Trả lời

41

Bạn phải thực hiện lời gọi phương thức của bạn trong Linq-to-Objects bối cảnh, bởi vì ở phía bên cơ sở dữ liệu đó gọi phương thức sẽ không có ý nghĩa - bạn có thể làm điều này bằng AsEnumerable() - về cơ bản phần còn lại của các truy vấn sau đó sẽ được đánh giá là một trong bộ sưu tập bộ nhớ sử dụng Linq-to-Objects và bạn có thể sử dụng phương pháp gọi như mong đợi:

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() }) 
+0

Câu trả lời hay, Cảm ơn – EgyEast

+0

Tôi chỉ muốn đảm bảo, vì vậy nó lặp lại số đếm hai lần, phải không? Trước tiên, trước '.AsEnumerable()' và thứ hai, sau '.AsEnumerable()'? –

8

Bạn sẽ muốn chia nó thành hai câu. Trả lại kết quả từ truy vấn (đó là những gì sẽ nhấn cơ sở dữ liệu), và sau đó liệt kê các kết quả lần thứ hai trong một bước riêng biệt để chuyển đổi bản dịch sang danh sách đối tượng mới. "Truy vấn" thứ hai này sẽ không nhấn vào cơ sở dữ liệu, vì vậy bạn sẽ có thể sử dụng someMethod() bên trong nó.

LINQ-to-Entities là một điều kỳ lạ, vì nó làm cho quá trình chuyển đổi truy vấn cơ sở dữ liệu từ C# cực kỳ liền mạch: nhưng bạn luôn phải tự nhắc mình, "C# này sẽ được dịch sang một số câu lệnh SQL . " Và kết quả là, bạn phải tự hỏi, "Tất cả C# này có thực sự được thực hiện như SQL không?" Nếu không thể - nếu bạn đang gọi someMethod() bên trong - truy vấn của bạn sẽ gặp sự cố. Và giải pháp thông thường là chia nó ra.

(Câu trả lời khác từ @BrokenGlass, sử dụng .AsEnumerable(), về cơ bản là một cách khác để làm việc đó.)

0

Đó là một câu hỏi cũ, nhưng Tôi thấy không ai đề cập đến một "hack", cho phép cal l phương pháp trong khi lựa chọn mà không nhắc lại. Ý tưởng là sử dụng hàm tạo và trong hàm tạo, bạn có thể gọi bất cứ điều gì bạn muốn (ít nhất nó hoạt động tốt trong LINQ với NHibernate, không chắc chắn về LINQ2SQL hoặc EF, nhưng tôi đoán nó sẽ giống nhau). Dưới đây tôi có mã nguồn cho chương trình điểm chuẩn, có vẻ như cách tiếp cận lặp lại trong trường hợp của tôi chậm hơn gấp đôi so với phương thức khởi tạo và tôi đoán không có gì lạ - logic nghiệp vụ của tôi rất nhỏ, vì vậy những thứ như vấn đề phân bổ bộ nhớ và lặp lại.

Ngoài ra tôi muốn có cách nào tốt hơn để nói, rằng đây hay không nên cố gắng thực hiện trên cơ sở dữ liệu,

// 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(); 
    } 
} 
Các vấn đề liên quan