2013-04-26 29 views
5

Tôi đang chiếu kết quả LINQ to SQL vào các lớp được đánh máy mạnh: Cha mẹ và Con. Sự khác biệt về hiệu năng giữa hai truy vấn này là lớn:truy vấn LINQ dự kiến ​​từ một đến nhiều được thực hiện liên tục

Query chậm - đăng nhập từ DataContext cho thấy một cuộc gọi riêng biệt để các db đang được thực hiện cho mỗi phụ huynh

var q = from p in parenttable 
     select new Parent() 
     { 
      id = p.id, 
      Children = (from c in childtable 
         where c.parentid = p.id 
         select c).ToList() 
     } 
return q.ToList() //SLOW 

Query nhanh - đăng nhập từ các chương trình DataContext một db truy vấn hit duy nhất trả về dữ liệu tất cả các yêu cầu

var q = from p in parenttable 
     select new Parent() 
     { 
      id = p.id, 
      Children = from c in childtable 
         where c.parentid = p.id 
         select c 
     } 
return q.ToList() //FAST 

tôi muốn buộc LINQ để sử dụng phong cách đơn truy vấn của ví dụ thứ hai, nhưng cư các lớp chuyên với trẻ em của họ đối tượng trực tiếp. nếu không, tài sản Trẻ em là IQuerierable<Child> phải được truy vấn để hiển thị đối tượng Trẻ em.

Các câu hỏi được tham chiếu dường như không giải quyết được tình huống của tôi. sử dụng db.LoadOptions không hoạt động. có lẽ nó yêu cầu loại là TEntity được đăng ký với DataContext.

DataLoadOptions options = new DataLoadOptions(); 
    options.LoadWith<Parent>(p => p.Children); 
    db.LoadOptions = options; 

Xin lưu ý: Cha mẹ và con là loại đơn giản, không phải là Table<TEntity> loại. và không có mối quan hệ theo ngữ cảnh giữa Phụ Huynh và Trẻ Em. các truy vấn con là ad-hoc.

Điểm mấu chốt của sự cố: trong ví dụ LINQ thứ hai, tôi thực hiện các câu lệnh IQueriable và không gọi hàm ToList() và vì lý do nào đó LINQ biết cách tạo một truy vấn đơn có thể truy xuất tất cả dữ liệu được yêu cầu. Làm cách nào để điền vào phép chiếu ad-hoc của tôi với dữ liệu thực tế như được thực hiện trong truy vấn đầu tiên? Ngoài ra, nếu có ai có thể giúp tôi giải thích tốt hơn câu hỏi của tôi, tôi sẽ đánh giá cao nó.

+0

Làm cách nào để 'Child' là một" loại đơn giản "? Nó phải là một loại ánh xạ. Và là 'parenttable' một' Bảng 'hoặc kết quả của một truy vấn LINQ trước đó? Một số câu lệnh linq có thể khiến L2S chuyển đổi từ việc tham gia thành N + 1. –

+1

Điểm đánh dấu trùng lặp: bạn có biết sự khác biệt giữa khung thực thể và linq với sql không? –

+0

@GertArnold Trong khi phần LINQ của EF/L2S thường làm cho các câu hỏi tương tự có chức năng trùng lặp, trong trường hợp * này * tôi tin rằng bạn hoàn toàn chính xác; chúng không phải là bản sao. Mở lại. –

Trả lời

0

Bạn phải đặt các tùy chọn chính xác cho tải dữ liệu của mình.

options.LoadWith<Document>(d => d.Metadata); 

Nhìn vào this

T.B. Include chỉ dành cho LINQToEntity.

+0

Điều này có vẻ như nó phải là câu trả lời, nhưng nó không hiệu quả với tôi. tôi đã thử dlo.LoadWith (p => p.Children). vẫn có nhiều lần truy cập db – Paul

+0

@Paul Bạn không cần sử dụng cha mẹ. Bạn đã tạo ra thực thể Cha mẹ bởi LINQ2SQL chưa? Sau đó, thực thể của bạn có chứa trẻ em đã có khi bạn yêu cầu phụ huynh từ ngữ cảnh. –

0

Truy vấn thứ hai nhanh chóng chính xác vì Trẻ em không được dân cư.

Và cái đầu tiên là chậm chỉ vì Trẻ em đang được phổ biến.

Chọn loại phù hợp nhất với nhu cầu của bạn, bạn chỉ đơn giản là không thể có các tính năng của chúng với nhau!

EDIT:

Như @Servy nói:

Trong truy vấn thứ hai của bạn, bạn không thực sự lấy bất kỳ thông tin về trẻ em. Bạn đã tạo các truy vấn, nhưng bạn chưa thực sự thực hiện chúng để có được kết quả của các truy vấn đó. Nếu bạn đã lặp lại danh sách, và sau đó lặp lại bộ sưu tập Trẻ em của mỗi mục bạn sẽ thấy nó mất nhiều thời gian như truy vấn đầu tiên.

1

Cách nhanh nhất tôi tìm thấy để thực hiện việc này là thực hiện truy vấn trả về tất cả kết quả rồi nhóm tất cả kết quả. Đảm bảo bạn làm một .ToList() trên truy vấn đầu tiên, để truy vấn thứ hai không thực hiện nhiều cuộc gọi.

Ở đây r phải có những gì bạn muốn thực hiện chỉ với một truy vấn db duy nhất.

  var q = from p in parenttable 
        join c in childtable on p.id equals c.parentid 
        select c).ToList(); 
      var r = q.GroupBy(x => x.parentid).Select(x => new { id = x.Key, Children=x }); 
+1

Thay vì tham gia và sau đó là nhóm, chỉ cần sử dụng GroupJoin. – Servy

5

Điều quan trọng cần nhớ là truy vấn LINQ dựa vào thực hiện hoãn lại. Trong truy vấn thứ hai của bạn, bạn không thực sự tìm nạp bất kỳ thông tin nào về trẻ em. Bạn đã tạo các truy vấn, nhưng bạn chưa thực sự thực hiện chúng để có được kết quả của các truy vấn đó. Nếu bạn đã lặp lại danh sách, và sau đó lặp lại bộ sưu tập Children của mỗi mục bạn sẽ thấy nó mất nhiều thời gian như truy vấn đầu tiên.

Truy vấn của bạn cũng vốn rất kém hiệu quả. Bạn đang sử dụng truy vấn lồng nhau để đại diện cho mối quan hệ Join. Nếu bạn sử dụng Join thay vì truy vấn sẽ có thể được tối ưu hóa một cách thích hợp bởi cả nhà cung cấp truy vấn cũng như cơ sở dữ liệu để thực thi nhanh hơn nhiều. Bạn cũng có thể cần phải điều chỉnh các chỉ mục trên cơ sở dữ liệu của mình để cải thiện hiệu suất. Dưới đây là cách tham gia có thể xem xét:

var q = from p in parenttable 
     join child in childtable 
     on p.id equals child.parentid into children 
     select new Parent() 
     { 
      id = p.id, 
      Children = children.ToList(), 
     } 
return q.ToList() //SLOW 
+0

Tôi biết câu hỏi là về LINQ to SQL, nhưng tôi nghĩ rằng tôi muốn đề cập rằng nếu bạn đang sử dụng Entity Framework, 'ToList()' không được yêu cầu trên 'children'. –

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