2011-12-16 33 views
6

Tôi có hai bảng cơ sở dữ liệu Liên hệ (Id, Tên, ...) và ContactOperationalPlaces (ContactId, MunicipalityId), nơi một liên hệ có thể được kết nối với một số ContactOperationalPlaces.Làm thế nào để thêm mệnh đề where vào linq join (lambda)?

Điều tôi đang cố gắng làm là tạo truy vấn (ASP .NET, C#) với IQueryable, chỉ chọn tất cả các liên hệ tồn tại trong bảng ContactOperationalPlaces, với một đô thị đã cho.

Truy vấn sql trông như thế này:

select * from Contacts c 
right join ContactOperationPlaces cop on c.Id = cop.ContactId 
where cop.MunicipalityId = 301; 

Với LINQ nó sẽ giống như thế này:

//_ctx is the context 
var tmp = (from c in _ctx.Contacts 
      join cop in _ctx.ContactOperationPlaces on c.Id equals cop.ContactId 
      where cop.MunicipalityId == 301 
      select c); 

Vì vậy, tôi biết làm thế nào để làm điều này nếu điểm là để chọn tất cả điều này cùng một lúc, tiếc là nó không phải. Tôi đang xây dựng một truy vấn dựa trên đầu vào của người dùng, vì vậy tôi không biết tất cả các lựa chọn cùng một lúc.

Vì vậy, đây là những gì mã của tôi trông giống như:

IQueryable<Contacts> query = (from c in _ctx.Contacts select c); 
//Some other logic.... 
/*Gets a partial name (string nameStr), and filters the contacts 
so that only those with a match on names are selected*/ 
query = query.Where(c => c.Name.Contains(nameStr); 
//Some more logic 
//Gets the municipalityId and wants to filter on it! :(how to? 
query = query.where(c => c.ContactOperationalPlaces ...........?); 

Sự khác biệt với hai nơi báo cáo là với người đầu tiên, mỗi lần tiếp xúc chỉ có một tên, nhưng với sự sau một số liên lạc có thể chứa một số các địa điểm hoạt động ...

Tôi đã tìm được một giải pháp, nhưng giải pháp này mang lại cho tôi một đối tượng không được xác định, chứa cả hai bảng. Và tôi không biết làm thế nào để tiếp tục với nó.

query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId, 
     (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301); 

Đối tượng trở về từ biểu thức này là System.Linq.Iqueryable < {c: Liên hệ, cảnh sát: ContactOperationalPlace}>, và nó không thể được đúc vào Danh bạ ...

Vì vậy, đó là vấn đề. Câu trả lời có lẽ khá đơn giản, nhưng tôi không thể tìm thấy nó ...

Trả lời

11

Bạn tạo một loại vô danh với cả hai đối tượng trước khi bạn mệnh đề where và lọc nó trên giá trị ContactOperationPlaces. Bạn chỉ cần chọn Liên hệ sau đó.

query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId, 
      (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301) 
            .Select(o => o.c) 
            .Distinct(); 
+2

và có lẽ thêm biệt() cho tiếp xúc –

+0

Cảm ơn điều chỉnh. –

+0

Cảm ơn bạn rất nhiều! Tôi biết rằng giải pháp sẽ khá đơn giản khi tôi tìm thấy nó. – linnkb

0

bạn có thể bỏ nó vào var và cố gắng sử dụng intellisense trên đó không?

var myCast = query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId, 
    (c, cop) => new {c, cop}).Where(o => o.cop.municipalityId == 301); 

Chỉ cần một ý nghĩ

1

Bạn không cần phải trả về các đối tượng mới trong hàm chọn kết quả. Các đại biểu cung cấp cả hai biến để bạn có thể chọn một hoặc khác, hoặc một số biến thể khác (mà sẽ yêu cầu một đối tượng mới). Hãy thử điều này:

query.Join(_ctx.ContactOperationPlaces, c => c.Id, cop => cop.ContactId, 
    (c, cop) => c).Where(o => o.cop.municipalityId == 301); 
+0

Tôi đã thử điều này trước đây, và vì tôi không làm như thế này: (c, cảnh sát) => mới {c, cop}, tôi sẽ không có cơ hội chọn cảnh sát ở mệnh đề where ... – linnkb

0

Tôi nghĩ sẽ dễ dàng hơn nếu bạn bắt đầu điều này làm 2 truy vấn khác nhau, sau đó kết hợp chúng. Tôi giả định mối quan hệ là Liên hệ (1 < -> nhiều) Địa chỉ liên lạc? Và cuối cùng, bạn sẽ hiển thị 1 mục trên mỗi Contactoperationplaces, không phải 1 mục cho mỗi Contact?

Làm điều đó như thế này:

IQueryable<Contacts> query = (from c in _ctx.Contacts select c); 

... 

query = query.Where(x=> x.Name.ToLower().Contains(nameStr.ToLower()); 

... 

IQueryable<ContactOperationPlaces> query_2 = 
    (from c in _ctx.ContactOperationPlaces 
     where query.Where(x=> x.Name == c.Contact.Name).Count() > 0 
     select c); 

//Now query_2 contains all contactoperationsplaces which have a contact that was found in var query 

Ngược lại, có một cách dễ dàng hơn để làm điều này, và đó là bằng cách bỏ qua phần đầu tiên hoàn toàn.

IQueryable<ContactOperationPlaces> query_2 = 
    (from c in _ctx.ContactOperationPlaces 
     where c.Contact.Name.ToLower().Contains(strName.ToLower()) 
     select c); 

Nếu bạn đang sử dụng Khung thực thể, bạn không phải tham gia bất kỳ khi nào bạn xác định liên kết giữa các bảng.

Bây giờ tôi nhìn vào nó, giải pháp thứ hai của tôi hiệu quả hơn và dễ dàng hơn nhiều. Nhưng nếu bạn cần phải làm một số chế biến khác Inbetween các lệnh này, giải pháp một công trình quá :)

Nếu bạn cần giải thích thêm, đừng ngần ngại hỏi :)

+0

Tôi muốn giữ liên lạc có một kết nối đến một cụ thể trong các trình liên lạc thích hợp, vì vậy tôi muốn một mục cho mỗi số liên lạc. Tôi biết giải pháp thứ hai là tốt nhất, nhưng như tôi đã giải thích trong câu hỏi của mình, tôi không thể chọn tất cả cùng một lúc. – linnkb

+0

là các bảng khác nhau được kết nối với một liên kết một-nhiều? Nếu vậy, đây là giải pháp tốt nhất của bạn. Nếu bạn có các tham gia khác mà liên hệ dựa vào, bạn nên thay thế chúng bằng cách làm một cái gì đó tương tự như ở trên. Vì EF thực hiện việc tham gia cho bạn và bạn chỉ phải nói những gì bạn muốn, tôi cho rằng việc tham gia bảng theo cách thủ công với EF là không hiệu quả theo mặc định (ngoại trừ một số trường hợp rất, rất khác thường). Không đổ lỗi cho bạn, nhưng tôi muốn đề nghị chỉ đạo rõ ràng từ việc tham gia thủ công vì bạn sẽ phải làm nhiều việc hơn, với ít phản hồi/gỡ lỗi hơn ... – Flater

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