2010-01-14 43 views
11

Tôi đang cố chuyển đổi truy vấn Sql thô cũ trong LINQ bằng Entity Framework tại đây.Toán tử "IN" trong LINQ

Nó đang sử dụng toán tử IN với một tập hợp các mục. Truy vấn là một cái gì đó như thế:

SELECT Members.Name 
FROM Members 
WHERE Members.ID IN (SELECT DISTINCT ManufacturerID FROM Products WHERE Active = 1) 
ORDER BY Members.Name ASC 

Kể từ khi sự trở lại của subquery không phải là một chuỗi duy nhất mà là một tập hợp các chuỗi Tôi không thể sử dụng phương pháp String.Contains().

Tôi nghĩ về làm một cái gì đó như:

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

và sau đó

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

nhưng nó dừng lại ở chứa nói rằng nó có lẽ không hợp lệ ... tôi không thể chọn activeProducts.ManufacturerID vì rõ ràng là sự khôn ngoan không có ở đó vì nó trả về một IQueryable ...

Điểm mấu chốt những gì tôi đang cố gắng làm ở đây là trả về danh sách các thành viên có ít nhất một sản phẩm hoạt động.

Bất kỳ gợi ý nào?

[sửa]

Dưới đây là đoạn code truy vấn đầy đủ ... Tôi đã thử với chứa trên biểu thức thứ hai, LINQ dường như không thích nó:

Server Error in '/' Application. LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable``1[System.String], System.String)' method, and this method cannot be translated into a store expression.

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID.ToString()); 

    var activeArtists = from artist in Master.DataContext.ContactSet 
         where activeProduct.Contains(artist.ID.ToString()) 
         select artist; 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 

[Chi tiết] ManufacturerID là một GUID vô hiệu hóa rõ ràng ...

Vì lý do nào đó, lớp ContactSet không chứa ny tham khảo các sản phẩm tôi đoán tôi sẽ phải làm một truy vấn tham gia, không có manh mối ở đây.

Trả lời

12
var activeMembers = (
from member in db.ContactSet 
where activeProducts.Select(x=>x.ID).Contains(member.ID)); 
5

Hãy thử where activeProducts.Contains(member.ID).
EDIT: Bạn đã thử nó mà không cần bất kỳ ToString s?

+0

Không hoạt động, gặp lỗi LINQ. – Erick

+0

Yup, và Linq vẫn không thích nó, tôi vừa phát hiện ra rằng ManufacturerID là một Guid? (nullable) ... nếu tôi làm một 'chọn ManufacturerID.Giá trị' Tôi có điều này: LINQ to Entities không nhận ra phương thức 'Boolean Contains [Hướng dẫn] (System.Linq.IQueryable'1 [System.Guid], System.Guid)' phương pháp, và phương pháp này không thể được dịch sang một cửa hàng biểu hiện. – Erick

+0

Điều này có hiệu quả như toán tử IN không? – tofutim

0

Thay vì điều này:

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

Hãy thử điều này:

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID)); 
+0

Cố gắng, Linq dường như không thích nó thực sự. – Erick

+0

Chính xác điều gì đã xảy ra khi bạn thử? – SLaks

+0

Lỗi ở trên bản chỉnh sửa =) – Erick

0

gì nếu bạn thay đổi tuyên bố (chưa được kiểm tra)?

where activeProducts.Contains(member.ID) 
0

Làm thế nào về vấn đề này ...

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID.ToString())); 
+0

Không hoạt động thực sự. – Erick

+0

Tôi nghĩ thay đổi này sẽ làm cho nó hoạt động ... var activeProducts = ( từ các sản phẩm trong db.ProductSet nơi product.Active == true chọn sản phẩm.ManufacturerID); var activeMembers = ( từ thành viên trong db.ContactSet nơi activeProducts.Select (x => x.id) .Contains (member.ID.ToString())); – spadelives

+0

'product.Active == true' là một chút dư thừa phải không? Chỉ 'product.Active' là đủ. – Askolein

2

Bạn có thể làm điều đó trong một truy vấn:

var q = from member in db.ContactSet 
     where member.Products.Any(p => p.IsActive) 
     select member; 
+0

Tôi đã phải đơn giản hóa tuyên bố nhưng có nhiều điều kiện để "ở đâu" ... Tôi đã chỉnh sửa bài đăng của mình để bao gồm toàn bộ mã trong thực tế. – Erick

+1

Bạn vẫn có thể làm điều đó trong một truy vấn. Di chuyển toàn bộ mệnh đề 'where' sang lệnh' Any'. – SLaks

+0

Không có liên kết nào từ ContactSet đến ProductSet apprently (oh cách tôi thích sửa đổi phần mềm của bên thứ 3), tôi đoán tôi sẽ phải thực hiện truy vấn ... – Erick

0

Một helper hoặc phương pháp khuyến nông sẽ làm việc tốt khi truy vấn đối với các đối tượng trong bộ nhớ. Nhưng đối với một cơ sở dữ liệu SQL, mã LINQ của bạn sẽ được biên dịch thành một cây biểu thức, được phân tích và dịch thành một lệnh SQL. Chức năng này không có khái niệm về phương pháp mở rộng tùy chỉnh hoặc phương pháp của các đối tượng khác như .Contains(...).

Có thể dễ dàng triển khai chức năng LINQ-To-SQL chuẩn của Microsoft. Nhưng miễn là họ không muốn, chúng tôi bất lực miễn là nó không phải là một chức năng nguồn mở.

Tất cả những gì bạn có thể làm là tạo QueryProvider của riêng bạn đi ngược lại cơ sở dữ liệu SQL. Nhưng nó sẽ khó khăn và nó sẽ chỉ cho một tính năng in một mình mà bạn đang thiếu.

Tuy nhiên, nếu bạn thực sự muốn đi con đường đó, có niềm vui: LINQ: BUILDING AN IQUERYABLE PROVIDER SERIES

0

Cuối cùng tôi quản lý để mã hóa một cái gì đó thực sự xấu xí, nhưng đó thực sự hoạt động! (lol)

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID).Distinct(); 

    var artists = from artist in Master.DataContext.ContactSet 
         select artist; 

    List<Evolution.API.Contact> activeArtists = new List<Evolution.API.Contact>(); 

    foreach (var artist in artists) 
    { 
     foreach(var product in activeProduct) 
     { 
      if (product.HasValue && product.Value == artist.ID) 
       activeArtists.Add(artist); 
     } 
    } 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 
0
var q = (from p in db.DOCAuditTrails 
     where p.ActionUser == "MyUserID" 
     && p.ActionTaken == "Not Actioned" 
     && p.ActionDate > DateTime.Parse("2011-09-13") 
      select p.RequisitionId).Distinct(); 

var DocAuditResults = db.DOCAuditTrails.Where(p 
    => q.ToArray().Contains(p.RequisitionId)); 
1

gì về điều này:

from m in members 
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null 
select m; 

bạn có thể chuỗi bất kỳ số lượng các điều kiện cần thiết trong mệnh đề where sử dụng & &

Ash ..

2
from m in members 
where products.Any(p => p.Active && p.ManufacturerID == m.ID) 
select m 

hoặc

from m in members 
join p in products on m.ID equals p.ManufacturerID 
where p.Active 
select m 
0

Nếu không biết ánh xạ chính xác nó là khó có thể nói những gì có thể được thực hiện và những gì không thể. Tôi sẽ giả định rằng không có bất kỳ sự tham gia nào. Trước hết bạn phải nhớ rằng mọi thứ trong cây biểu thức LINQ phải có một tương đương trong SQL. Như một số người khác đã lưu ý, bạn có một đối tượng.ToString() trong báo cáo LINQ của bạn.

Tuy nhiên có vẻ như những gì mọi người đã bỏ qua đề cập đến là bạn có HAI tập quán của đối tượng.ToSting(), cả hai đều phải được loại bỏ.

Tôi cũng sẽ tạo thêm một biến để thay đổi kiểu chụp của đóng được rõ ràng của DataContext (vì câu lệnh Linq giống như một lambda, và bị trì hoãn được đánh giá. Nó sẽ cần lấy toàn bộ biến Master. đã nói rằng mọi thứ trong LINQ của bạn phải có một tương đương trong SQL. Do Master không thể tồn tại trong SQL, không có thuộc tính/cột/ánh xạ DataContext nào cho kiểu Master).

var context = Master.DataContext; 
var activeProduct = from product in context.ProductSet 
        where product.Active == true 
         && product.ShowOnWebSite == true 
         && product.AvailableDate <= DateTime.Today 
         && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
        select product.ManufacturerID; 

var activeArtists = from artist in context.ContactSet 
        where activeProduct.Contains(artist.ID) 
        select artist; 

Tôi hy vọng những thay đổi ở trên phù hợp với bạn.

Trong nhiều trường hợp, vấn đề với LINQ to ORM có thể được truy nguyên trở lại biểu thức LINQ của bạn không bắt mồi (DateTime, int, string, vv) và lớp ORM non (DataContext/EntityObject v.v.). Gotcha chính khác là việc sử dụng các hàm và toán tử không được ORM trưng ra (có thể ánh xạ các hàm do người dùng định nghĩa tới hàm .net thông qua ORM, nhưng tôi sẽ không khuyến cáo nó do các vấn đề lập chỉ mục).

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