2009-12-17 38 views
13

này công trình trong LINQ-to-SQL:Tại sao Entity Framework không thể sử dụng ToString() trong một câu lệnh LINQ?

var customersTest = from c in db.Customers 
       select new 
       { 
        Id = c.Id, 
        Addresses = from a in db.Addresses where c.Id.ToString() == 
         a.ReferenzId select a 
       }; 

foreach (var item in customersTest) 
{ 
    Console.WriteLine(item.Id); 
} 

Nhưng một ví dụ tương tự trong Entity Framework được một thông báo lỗi nói rằng về cơ bản nó không thể "dịch nó to SQL", đây là thông báo ban đầu lỗi trong Tiếng Đức:

" 'LINQ to Entities' erkennt chết Methode 'System.String ToString()' nicht, und diese Methode kann nicht trong einen Speicherausdruck übersetzt werden. "

dịch:.

" 'LINQ to Entities' không công nhận Phương pháp 'System.String ToString()', phương pháp này không thể được dịch ra tiếng một biểu thức bộ nhớ

Bất cứ ai cũng có thể làm sáng tỏ cách chúng tôi có thể đưa loại tuyên bố này hoạt động trong Khung thực thể hoặc giải thích lý do tại sao lỗi của anh ấy?

+0

Id của bạn đã là một chuỗi chưa? Không chắc chắn lý do tại sao điều đó sẽ khiến EF trở thành vấn đề nhưng thông báo lỗi dường như chỉ ra rằng đó là một trở ngại. Bạn muốn string.ToString() sẽ hoạt động khá nhanh: P –

+0

Id là một số nguyên trong ví dụ L2S. Trong ví dụ EF thực sự của chúng tôi nó là một GUID. Thú vị ToString() là intellisense và nó biên dịch nhưng nhận được lỗi thời gian chạy. –

+0

@Edward Tanguay: Tôi vừa xem câu hỏi của bạn và thêm một câu trả lời, tôi hy vọng nó vẫn hữu ích ngay cả sau một thời gian dài ... – Matt

Trả lời

9

Chỉ cần đặt: LINQ to Entities không biết về chuyển đổi từ loại ID của bạn thành chuỗi.

Loại c.ID là gì? Có bất kỳ lý do nào vì sao đó là một loại cho ID, nhưng một loại khác cho số ReferenzId? Nếu có thể, làm cho chúng cùng loại, tại thời điểm đó bạn sẽ không gặp vấn đề nữa. Tôi không biết nếu có những cách khác để thực hiện chuyển đổi trong LINQ to Entities - có thể có - nhưng sắp xếp các loại sẽ sạch hơn.

Bằng cách này, điều này thực sự trông giống như đó là một tham gia:

var query = from c in db.Customers 
      join a in db.Addresses on c.Id equals a.ReferenzId into addresses 
      select new { Id = c.Id, Addresses = addresses }; 

EDIT: Để đáp ứng với nhận xét của bạn - ToString xuất hiện trong IntelliSense vì trình biên dịch không có ý tưởng thực những gì truy vấn của bạn sẽ có ý nghĩa hay nó sẽ được dịch như thế nào. Nó hoàn toàn hợp lệ C#, và có thể tạo ra một cây biểu thức hợp lệ - đó chỉ là EF không biết cách chuyển đổi cây biểu thức đó thành SQL.

Bạn có thể thử sử dụng Convert.ToString(c.Id) thay vì chỉ gọi c.Id.ToString() ...

+0

đó là một cơ sở dữ liệu lịch sử mà chúng tôi đang sử dụng ở đó a.ReferenzID thực sự là một chuỗi, những lý do được rằng nó có thể được tham gia vào một int trong một bảng nhưng một GUID khác. –

+1

cảm ơn nhưng Convert.ToString (c.Id) cho chúng ta cùng một lỗi –

+0

Thử chuyển đổi theo cách khác? Gọi 'new Guid (a.ReferenzId)' thay thế? –

-2

LINQ to Entities như xa như tôi hiểu nó (cho v1) là rất primative. Trong các từ khác, nó không biết cách sử dụng phương thức mở rộng "ToString()" và tạo ra SQL cho nó.

Trong LINQ to SQL, nó thực thi phương thức mở rộng "ToString()" trước khi tạo SQL. Sự khác biệt là LINQ to Entities sử dụng IQueryable thay vì IEnumerable.

NHƯNG, từ những gì tôi nhớ truyền nên hoạt động (vì truyền là một kiểu dữ liệu và SQL biết về CAST()).

Vì vậy,

c.Id.ToString() thực sự phải là (chuỗi) c.Id

(cũng phải chắc chắn là (chuỗi) chứ không phải (Chuỗi)).

Một trong những nhược điểm mà tôi sẽ nói về việc sử dụng Lambda (trong Entity Framework) để tạo biểu thức SQL thay vì LINQ thuần túy.

Hãy ghi nhớ quá, rằng việc sử dụng CAST ở phía bên trái của dấu bằng trong SQL là một chút bệnh thực hiện :-)

+0

xin lỗi cho DV muộn: '(chuỗi) c.Id' sẽ không biên dịch với" Không thể chuyển đổi loại 'int' thành 'chuỗi'. " –

+0

Từ những gì bạn đã viết, người ta có thể nghĩ rằng Linq2SQL sử dụng IEnumerable hơn là IQueryable, mà tất nhiên là không đúng sự thật. –

+1

@Wiktor Zychla: Tôi đã xác minh nó, bạn không thể chỉ đơn giản là đúc thành chuỗi trong một truy vấn EF bằng cách sử dụng '(string)' làm toán tử cast. Nhưng có một nhìn vào câu trả lời của tôi, tôi có hai lựa chọn ngay bây giờ (đăng [ở đây] (http://stackoverflow.com/a/17447930/1016343)) đang làm việc tốt cho tôi. – Matt

8

Nó làm cho không có ý nghĩa với tôi lý do tại sao Linq2EF không dịch .ToString() thành một SQL thích hợp tuyên bố, như Linq2SQL, chỉ có đội ngũ dev của Microsoft biết lý do tại sao họ chưa triển khai nó. :-(

Nhưng bạn có thể nâng cao ưu tiên để thực hiện nó nếu bạn bỏ phiếu cho tính năng này bằng cách làm theothis link.

May mắn cũng có 2 cách giải quyết có sẵn, cả hai chúng tôi đã sử dụng gần đây trong truy vấn EF:


I) gì giúp tôi để có được khắc phục hạn chế này là để thay đổi truy vấn vào một danh sách, như vậy:

var customersList = (from c in db.Customers 
      select c).ToList(); // converts to IEnumerable<T> ... 
var customersTest = (from c in customersList 
      select new {Id=c.ID.ToString()}); // ... which allows to use .ToString() 

Tuyên bố .ToList() cải để IEnumerable<T>, nơi .ToString() có sẵn. Lưu ý, Tùy thuộc vào yêu cầu, bạn có thể sử dụng .AsEnumerable(), có lợi thế là trì hoãn thực thi được hỗ trợ tốt hơn nếu bạn có nhiều truy vấn LINQ tùy thuộc lẫn nhau hoặc nếu bạn đang sử dụng các giá trị tham số khác nhau (nhiều nhờ có Divega cho gợi ý này!).

Sau đó bạn có thể sử dụng truy vấn này như bạn muốn, ví dụ .:

var customersTest2 = from c in customersTest     
    select new 
      { 
       Id = c.Id, 
       Addresses = from a in db.Addresses where c.Id == a.ReferenzId select a 
      }; 

Tất nhiên nếu bạn cần bạn có thể thêm nhiều thuộc tính cho các đối tượng của customersTest theo yêu cầu. Bạn cũng có thể tối ưu hóa truy vấn ở trên, tôi chỉ sử dụng 3 bước để dễ đọc ví dụ này.


II) Đối với chuyển đổi đơn giản, và nếu bạn có để tái sử dụng các truy vấn được tạo ra trong truy vấn con hơn nữa (và nó cần phải duy trì IQueryable), sử dụng SqlFunctions từ System.Data.Objects.SqlClient, họ sẽ được dịch sang các truy vấn SQL một cách chính xác.

Ví dụ 1: Ngày chuyển đổi (bạn phải sử dụng dateparts như dưới đây thể hiện)

var customersTest = from c in db.Customers 
    select new { 
     strDate=SqlFunctions.DateName("dd", c.EndDate) 
      +"."+SqlFunctions.DateName("mm", c.EndDate) 
      +"."+SqlFunctions.DateName("yyyy", c.EndDate) 
    } 

Ví dụ 2: Numeric để chuyển đổi chuỗi

var customersTest = from c in db.Customers 
    select new { 
     strID=SqlFunctions.StringConvert((double)c.ID) 
    } 

Điều này sẽ giúp bạn ra khỏi hầu hết các tình huống mà yêu cầu chuyển đổi thành chuỗi.


Cập nhật: Nếu bạn làm theo các liên kết Tôi đưa cho bạn ở phần đầu của câu trả lời của tôi, tính năng này mất tích đã đồng thời nhận 75 phiếu và bây giờ là implemented by Microsoft in EF 6.1 (cuối cùng!). Để tất cả những người tham gia: Cảm ơn bạn đã bỏ phiếu! Giọng của bạn đã được nghe.

Ví dụ:

var query = from e in context.Employees where e.EmployeeID.ToString() == "1" select e; 

bây giờ sẽ được dịch sang:

DECLARE @p0 NVarChar(1000) = '1' 
SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], 
    [t0].[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address],[t0].[City], 
    [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Extension], 
    [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath] 
FROM [Employees] AS [t0] 
WHERE (CONVERT(NVarChar,[t0].[EmployeeID])) = @p0 

ví dụ: e.EmployeeID.ToString() dịch để (CONVERT(NVarChar,[t0].[EmployeeID])).

+1

Bạn có thể sử dụng AsEnnumerable() thay vì ToList(). Đây có thể là một lựa chọn tốt hơn nếu bạn muốn duy trì thực thi trì hoãn và khả năng thực thi truy vấn nhiều lần với các giá trị tham số khác nhau. – divega

+0

@divega: Cảm ơn bạn đã gợi ý, tôi đã thử nó và nó hoạt động tốt! Tôi cũng đã cập nhật câu trả lời của mình. – Matt

+0

** Một gợi ý khác **: Nếu bạn đang sử dụng 'SqlFunctions.StringConvert (...)', thì bạn sẽ cần '.Trim() 'trong một số trường hợp để loại bỏ các khoảng trống mà hàm chuyển đổi tạo ra. Đáng ngạc nhiên, bạn có thể sử dụng 'SqlFunctions.StringConvert (...). Trim()' trong một truy vấn! :-) – Matt

6

Khung thực thể 6.1 RTM vừa được phát hành bây giờ hỗ trợ .ToString()

+0

Có, tôi nhận thấy một cách trùng hợp rằng nó hỗ trợ nó. Nhưng điều này không được đề cập trong bất kỳ tài liệu tham khảo nào. Bạn có thể vui lòng cung cấp thông tin tham khảo về vấn đề này không? –

+0

Được đăng trong câu trả lời ở trên http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2327346-support-tostring-method-in-linq-to-entities –

Các vấn đề liên quan