2013-08-09 35 views
5

phép nói rằng chúng ta có:biểu LINQ để lọc một danh sách bộ sưu tập thực thể, và duy trì danh sách các thực thể

public class Foo 
{ 
    public long Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Bar> { get; set; } 
} 

public class Bar 
{ 
    public long Id { get; set; } 
    public int Age { get; set; } 

    public virtual Foo { get; set; } 
    public long FooId { get; set; } 
} 

dữ liệu của chúng tôi có thể trông giống như thế này: (giả List<Foo>)

// Forget the syntax, just to demonstrate data 
foo[0] = new Foo{ Id = 1, Name = "A", Bar = { collection of Bars with Ages over 10 }}; 
foo[1] = new Foo{ Id = 2, Name = "B", Bar = { collection of Bars with Ages over 20 }}; 
foo[2] = new Foo{ Id = 3, Name = "C", Bar = { collection of Bars with Ages under 10 }}; 

Bây giờ, hãy nói rằng tôi muốn tất cả những người đó là Foo s nhưng chỉ với số Bar của họ bao gồm một số Bar với độ tuổi từ 5-25.

Đối với một cái gì đó như thế này, tôi sẽ làm việc ngược lại và nhận được tất cả các quán bar, sau đó nhận được tất cả các Foos liên quan đến những quán bar, và tái bản đồ các Bars trở lại Foo. Có vẻ quá phức tạp.

Để được rõ ràng hơn - Tất cả Foos với chỉ Bars của họ với lứa tuổi từ 5 đến 25 :)

+0

http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – Androiderson

+0

Câu hỏi của bạn là loại không rõ ràng - bạn có muốn tất cả 'Foo's với duy nhất của họ' Bar's với độ tuổi từ 5 đến 25 hoặc bạn chỉ muốn 'Foo' có 'Bar' với độ tuổi từ 5 đến 25? –

+0

Một cách, chưa được đề xuất, là triển khai một phương thức mở rộng trên Foo với khai báo giống như: 'GetBarsBetween (int lower, int upper);' và đơn giản sử dụng phương thức extenion này để lọc và truy xuất các thanh chính xác trong một Foo. Sau đó, bạn có thể chỉ cần chọn tất cả Foo's 'where foo.GetBarsBetween (5, 25) .Any()'. Điều này không yêu cầu bất kỳ phân bổ memomry bổ sung hoặc cơ cấu lại các đối tượng hiện tại của bạn. Hai nhược điểm, bạn không thể đơn giản sử dụng mã hiện có để làm việc với các thanh được lọc và thời gian tính toán có phần cao hơn. – Polity

Trả lời

4

Nếu bạn muốn chọn tất cả Foo 's và duy nhất của họ Bar' s giữa tuổi của 5 và 25:

var results = 
    from f in db.Foos 
    select new 
    { 
     f.Id, 
     f.Name, 
     Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25) 
    }; 

Điều này sẽ tạo ra một loại ẩn danh. Nếu bạn cần tạo một loại tên (ví dụ nếu bạn cần phải trả lại kết quả từ một chức năng như một List<T>) có lẽ bạn nên tạo một tên kiểu đơn giản cho tập kết quả này:

public class FooWithFilteredBarResult // replace with whatever name you like 
{ 
    public long Id { get; set; } 
    public string Name { get; set; } 
    public IEnumerable<Bar> { get; set; } 
} 


List<FooWithFilteredBarResult> results = 
    (from f in db.Foos 
    select new FooWithFilteredBarResult 
    { 
     Id = f.Id, 
     Name = f.Name, 
     Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25) 
    }) 
    .ToList(); 
+0

'let' mang một hiệu suất khá lớn trong linq cho các đối tượng, chỉ cần đứng lên. – doogle

+0

Câu trả lời thứ hai cho câu trả lời của bạn là những gì tôi đang tìm kiếm. Có cách nào để bỏ qua phải chỉ định tất cả các thuộc tính của Foo, thay vào đó chỉ cần "tự động chọn" chúng và đặt điều kiện trên các thanh? – Josh

+0

@Josh Không, rất tiếc là không có, mặc dù bạn luôn có thể cố gắng lọc chúng sau này, ví dụ: khi bạn đang đánh giá kết quả. Ngoài ra, bạn chỉ cần xác định các thuộc tính của 'Foo' mà bạn cần. Nếu có 50 tài sản khác mà bạn không quan tâm, bạn có thể loại bỏ chúng. –

1
var r = Foos.Select(x => new Foo() 
     { 
      Id = x.Id, 
      Name = x.Name, 
      Bars = x.Bars.Where(y => y.Age <= 25 && y.Age >= 5).ToList() 
     }); 
+0

Điều này về cơ bản giống như câu trả lời # 2 tùy chọn @pswg, nhưng nó không cho phép tôi tạo một Foo mới? Nó nói rằng thực thể hoặc kiểu phức không thể được xây dựng trong một truy vấn LINQ to Entities. – Josh

+0

@Josh có vẻ như chúng tôi đã gửi cùng một lúc. Hmm .. tôi không biết bạn đang nói về việc lọc các bản ghi thông qua EF. hãy suy nghĩ về nó. – zsong

1

này cũng sẽ chỉ chọn độc đáo của Foo.

bars.Where(b => b.Age >= 5 && b.Age <= 25).GroupBy(b => b.FooId).Select(g => g.FirstOrDefault().Foo).ToList(); 
+0

Tôi nhận được GroupBy. Tại sao chọn/FirstOrDefault? – Josh

+0

Để chỉ chọn Foo riêng biệt, nếu không bạn có thể kết thúc với lặp lại theo câu hỏi và cấu trúc. – doogle

+0

Điều đó dường như trả về Bars? – Josh

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