2013-10-15 16 views
10

Tôi có bảng NxN, hãy tưởng tượng:LINQ to Entities Bao gồm + Trong trường hợp Phương pháp

tài khoản (id, ...) < - UserAddresses (id, userId, AddressID, kích hoạt, ...) -> Địa chỉ (id , ...)

UserAddresses chứa FK cho người dùng và địa chỉ. Đối với những gì tôi biết, Thực thể được tạo bởi Người dùng khung thực thể, chứa một bộ sưu tập cho UserAddresses. Địa chỉ chứa một bộ sưu tập để UserAddresses, và một UserAddress cụ thể chứa một refenrece cho người dùng và một địa chỉ.

Bây giờ tôi muốn thực hiện truy vấn tiếp theo bằng LINQ. Đối với một id người dùng cụ thể, chỉ nhận được userAddresses với cờ đã bật được đặt thành true. Đối với một id người dùng cụ thể, userAddresses có thể chứa nhiều mục nhập nhưng chỉ có một mục được đặt cho người dùng cụ thể này.

Truy vấn tôi có thể làm là:

context.User.Include(x => x.UserAddresses) 
      .Include(x => x.UserAddresses.Select(y => y.Address)) 
      .Single(x => x.id == USER_ID) 

nhưng những gì tôi thực sự muốn không phải là để tải tất cả UserAddresses cho người dùng đó ... Chỉ một trong đó có chứa kích hoạt, setted TRUE!

Ai đó có thể giúp tôi thực hiện truy vấn này?

+0

Bạn đang sử dụng loại 'Bao gồm' nào? Theo tôi biết phương thức 'Include' của' System.Data.Objects.ObjectQuery' chỉ nhận được 1 đối số của chuỗi? –

+0

@KingKing Tôi đã thực hiện một phương thức mở rộng, định dạng biểu thức lambda thành chuỗi và chuyển cho phương thức ObjectQuery bao gồm "native". – anotherNeo

+0

Nếu vậy, câu trả lời cho vấn đề của bạn là 'không thể', 'Bao gồm' không mạnh như vậy, bạn không thể thực hiện bất kỳ' bộ lọc' nào trước khi đưa vào. –

Trả lời

14

Không có cách nào để EF tải một phần thuộc tính liên kết. Hãy thử chọn loại ẩn danh để chỉ lấy những gì bạn cần:

var result = context.User 
    .Where(u => u.Id == userId) 
    .Select(u => new { 
     Addresses = u.UserAddresses.Select(ua => ua.Address) 
      .Where(a => a.Enabled), 
     User = u // if you need this as well 
    }) 
    .Single(); 

Kết quả này sẽ không tải.User.UserĐịa chỉ, nhưng kết quả.Địa chỉ sẽ có chính xác những gì bạn muốn.

Nếu bạn thực sự muốn trả lại mọi thứ như một phần của lớp người dùng, bạn cần tách kết quả.User và sau đó cập nhật kết quả.User.UserAddresses để trỏ đến kết quả.

+0

Tôi cần trả về thực thể Người dùng với tất cả mọi thứ liên quan, nhưng không phải tất cả Bộ sưu tập được ánh xạ .. Vì vậy, tôi nghĩ loại ẩn danh là không đúng:/ – anotherNeo

+0

@goncaloRD: Thật không may là điều kiện 'where' không thể sử dụng' Bao gồm'. Đây là lựa chọn tốt nhất của bạn. – Ocelot20

+0

@ChaseMedallion cảm ơn, Đây chính xác là những gì tôi cần. Truy vấn được thực hiện hoàn hảo và các đối tượng EF được ánh xạ theo cách tôi muốn. Tôi đã tạo một Loại để có đối tượng của tôi được đánh máy, được sử dụng trong Lớp kinh doanh của tôi. – anotherNeo

1

Một tùy chọn khác thay thế là sử dụng Load() thay vì Bao gồm():

var foundUser = context.User.Single(x => x.Id == USER_ID); 

context.Entry(foundUser).Collection(u => 
u.UserAddresses).Query().Where(userAddress => 
userAddress.Enabled).Load(); 

Hãy ghi nhớ rằng Load() phương pháp có thể được bỏ qua bởi EF trong một số kịch bản:

  1. nếu bạn đang sử dụng EF cùng với tính năng Lazy Loading, tìm nạp đối tượng của bạn mang tất cả các bộ sưu tập liên quan đã được đánh dấu là Virtual trong lớp của bạn. Vì vậy, bằng cách thực hiện việc này:

    ngữ cảnh.User.Single (x => x.id == USER_ID);

    bạn sẽ nhận được tất cả các UserAddresses được liên kết với Người dùng trừ khi bạn tắt tải Lặng cho bộ sưu tập của mình bằng cách xóa từ khóa ảo khỏi thuộc tính trong lớp người dùng.

  2. Nếu bạn đang thêm/xóa bộ sưu tập UserAddresses trong ngữ cảnh chương trình và cuộc gọi của bạn.SaveChanges(); mà không xử lý bối cảnh của bạn, lần sau khi bạn tải đối tượng Người dùng, bộ sưu tập UserAddresses sẽ được tải từ bộ đệm ẩn ngữ cảnh EF không phải từ DB (những thay đổi mới nhất của bạn). Trong trường hợp này, bạn cần phải vứt bỏ bối cảnh của bạn và khởi tạo bối cảnh mới trước khi nhận Người dùng từ ngữ cảnh. Ví dụ nếu bạn có User của bạn với 5 mục trong bộ sưu tập UserAddresses của bạn, và bạn làm cho một trong các mục bị vô hiệu hóa (item.Enabled = false) và sau đó gọi context.SaveChanges() mà không xử lý ngữ cảnh của bạn, lần sau khi bạn nhận đối tượng User từ cùng một bối cảnh, nó đã có 5 mục trong bộ sưu tập của nó xuất phát từ bộ nhớ cache ngữ cảnh và nó bỏ qua phương thức Load() của bạn.

PS:

Lazy tính năng tải là ON nếu tất cả các điều kiện dưới đây được áp dụng:

  1. context.Configuration.LazyLoadingEnabled = true;
  2. context.Configuration.ProxyCreationEnabled = true;
  3. UserAddresses đã được xác định ảo trong lớp người dùng của bạn.
Các vấn đề liên quan