Khung thực thể - Lỗi “Không thể tạo giá trị không đổi của loại 'Loại đóng cửa'…”


79

Tại sao tôi gặp lỗi:

Không thể tạo một giá trị không đổi của loại 'Loại đóng cửa'. Chỉ các kiểu nguyên thủy (ví dụ: Int32, String và Guid) được hỗ trợ trong ngữ cảnh này.

Khi tôi cố gắng liệt kê truy vấn Linq sau đây?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

Cập nhật : Nếu tôi thử các bước sau chỉ để cố gắng cô lập vấn đề, tôi gặp lỗi tương tự:

where upperSearchList.All(arg => arg == arg) 

Vì vậy, có vẻ như vấn đề là với phương pháp Tất cả, phải không? Bất kỳ đề xuất?

Câu trả lời:


68

Có vẻ như bạn đang cố gắng thực hiện tương đương với điều kiện "WHERE ... IN". Kiểm tra Cách viết truy vấn kiểu 'WHERE IN' bằng cách sử dụng LINQ cho Thực thể để biết ví dụ về cách thực hiện kiểu truy vấn đó với LINQ cho Thực thể.

Ngoài ra, tôi nghĩ rằng thông báo lỗi đặc biệt không hữu ích trong trường hợp này vì .Containskhông có dấu ngoặc đơn theo sau, điều này khiến trình biên dịch nhận ra toàn bộ vị từ là một biểu thức lambda.


Cảm ơn Daniel. Cú pháp tương tự hoạt động tốt với Linq đơn giản. Vì vậy, có vẻ như vấn đề là với EF trong .Net 3.5 SP1 phải không? Vùng chứa không có dấu ngoặc đơn tương đương với: where upperSearchList.All (x => (person.FirstName + person.LastName) .Contains (x)). ToList ();
Gus Cavalcanti

Nếu tôi thử ở nơi upperSearchList.All (arg => arg == arg) thì nó cũng gặp lỗi tương tự. Vì vậy, vấn đề là với phương pháp Tất cả ...
Gus Cavalcanti

2
LINQ to Entities là một công nghệ tuyệt vời, nhưng công cụ dịch SQL còn hạn chế. Tôi không thể đặt tay vào tài liệu chính thức, nhưng theo kinh nghiệm của tôi, nếu truy vấn bao gồm nhiều hơn các hàm toán học và chuỗi / ngày cơ bản, thì nó sẽ không hoạt động. Bạn đã có cơ hội kiểm tra bài viết mà tôi đã liên kết chưa? Nó mô tả một quá trình chuyển đổi truy vấn kiểu "WHERE..IN" thành một dạng mà LINQ thành Thực thể sau đó có thể dịch sang SQL.
Daniel Pratt

Bạn không thể sử dụng con trỏ hàm trong linq cho các thực thể. Nhà cung cấp không biết cách đào nó ra khỏi cây biểu thức để chuyển nó thành SQL.
Sinaesthetic

@DanielPratt liên kết của bạn bị hỏng
Mick

11

Tôi đã dành 6 tháng qua để chiến đấu với hạn chế này với EF 3.5 và mặc dù tôi không phải là người thông minh nhất trên thế giới, nhưng tôi khá chắc rằng mình có điều gì đó hữu ích để cung cấp về chủ đề này.

SQL được tạo ra bằng cách trồng một cây biểu thức "kiểu HOẶC" cao 50 dặm sẽ dẫn đến một kế hoạch thực thi truy vấn kém. Tôi đang xử lý một vài triệu hàng và tác động là đáng kể.

Có một thủ thuật nhỏ mà tôi tìm thấy để thực hiện một SQL 'in' giúp ích nếu bạn chỉ đang tìm kiếm một loạt các thực thể theo id:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

trong đó pkIDColumn là tên cột id khóa chính của bảng Entity1 của bạn.

NHƯNG HÃY TIẾP TỤC ĐỌC!

Điều này là tốt, nhưng nó yêu cầu rằng tôi đã có id của những gì tôi cần tìm. Đôi khi tôi chỉ muốn các biểu hiện của mình tiếp cận với các mối quan hệ khác và những gì tôi có là tiêu chí cho những mối quan hệ được kết nối đó.

Nếu có nhiều thời gian hơn, tôi sẽ cố gắng biểu diễn điều này một cách trực quan, nhưng tôi không nên chỉ nghiên cứu câu này một chút: Hãy xem xét một lược đồ với các bảng Person, GovernmentId và GovernmentIdType. Andrew Tappert (Person) có hai thẻ id (GovernmentId), một từ Oregon (GovernmentIdType) và một từ Washington (GovernmentIdType).

Bây giờ tạo một edmx từ nó.

Bây giờ, hãy tưởng tượng bạn muốn tìm tất cả những người có một giá trị ID nhất định, giả sử 1234567.

Điều này có thể được thực hiện với một lần truy cập cơ sở dữ liệu duy nhất với điều này:

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

Bạn có thấy truy vấn con ở đây không? Sql được tạo sẽ sử dụng 'nối' thay vì truy vấn phụ, nhưng hiệu quả là như nhau. Ngày nay, máy chủ SQL vẫn tối ưu hóa các truy vấn con thành các phép nối bên dưới, nhưng dù sao ...

Chìa khóa để làm việc này là .Any bên trong biểu thức.


8

Tôi đã tìm ra nguyên nhân gây ra lỗi (Tôi đang sử dụng Framework 4.5). Vấn đề là EF, một kiểu phức tạp, được chuyển vào tham số "Chứa", không thể dịch thành một truy vấn SQL. EF có thể sử dụng trong một truy vấn SQL chỉ các kiểu đơn giản như int, string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAll cung cấp danh sách các đối tượng có kiểu phức tạp (ví dụ: "Hàm"). Vì vậy, ở đây tôi sẽ cố gắng nhận một phiên bản của kiểu phức tạp này trong truy vấn SQL của tôi, tự nhiên không thể hoạt động!

Nếu tôi có thể trích xuất từ ​​danh sách của mình, các tham số phù hợp với tìm kiếm của tôi, tôi có thể sử dụng:

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

Bây giờ EF không còn có kiểu phức tạp "Hàm" để hoạt động, mà ví dụ với kiểu đơn giản (dài). Và điều đó hoạt động tốt!


0

Tôi nhận được thông báo lỗi này khi đối tượng mảng của tôi được sử dụng trong hàm .All là null Sau khi tôi khởi tạo đối tượng mảng, (trong trường hợp của bạn là upperSearchList), lỗi đã biến mất Thông báo lỗi gây hiểu lầm trong trường hợp này

nơi upperSearchList.All (arg => person.someproperty.StartsWith (arg)))

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.