如題,大多數網上關於 LINQ Join 的示例都是以 from x in TableA join ... 這樣的形式,這種有好處,也有劣勢,就是在比如我們使用的框架如果已經封裝了很多方法,比如分頁方法。而我們的業務方法只需要在 Service 層調用框架的分頁方法,同時注入條件拼接的委托就可以了。而這時候,為了簡單,就會以調用 Join() 方法來實現關聯查詢,外部看起來好像是子查詢,而實際上 Entity Framework 生成 SQL 時,還是會以 Inner join 的形式來生成 SQL 語句,但不管怎樣,我們還是解決了我們的實際需求,也就可以說成功了。
1. 數據庫
假設有 2 張表。Person 表和 City 表。Person 表的 CityID 關聯 City 表的 ID。
City 表:

Person 表:

2. 需求
現在,前台界面有一個 checkbox 復選框組,列出所有的城市,然后用戶可以選擇一個或多個,比如“深圳”和“北京”,分頁列出對應的人員。注意,前台界面只需要列出 Person 的 Id 和 Name 就可以了,不需要列出城市的名稱。
3. 代碼
PersonQueryCondition.cs
public class PersonQueryCondition { public IEnumerable<string> CityNameList { get; set; } }
PersonService.cs
public class PersonService : IPersonService { private readonly IRepository<Person> _personRepository; private readonly IRepository<City> _cityRepository; public PersonService(IRepository<Person> personRepository, IRepository<City> cityRepository ) { this._personRepository = personRepository; this._cityRepository = cityRepository; } /// <summary> /// 根據城市名稱列表獲取分頁實體 /// </summary> /// <param name="cityIdList"></param> /// <returns></returns> public List<Person> GetPagedList(PersonQueryCondition queryCondition, int pageIndex, int pageSize, out int recordCount) { return this._personRepository.GetListPagedByCondition<PersonQueryCondition>(c => c.Id > 0, CombineQuery, queryCondition, pageIndex, pageSize, out recordCount); } protected virtual IQueryable<Person> CombineQuery(IQueryable<Person> query, PersonQueryCondition queryCondition) { if (queryCondition == null) { return query; } if (queryCondition.CityNameList != null && queryCondition.CityNameList.Any()) { query = query.Join(_cityRepository.Table, p => p.CityID, c => c.Id, (p, c) => new { Person = p, City = c }) .Where(a => queryCondition.CityNameList.Contains(a.City.Name)) .Select(c => c.Person) .Distinct(); } return query; } }
請注意:如果 Person 和 City 是多對多的關系,即一個用戶可以在多個城市生活,一個城市也可以有多個用戶。那么如果要篩選即在 “深圳” 生活的人,又曾經在 “北京” 生活過的人,則 LINQ 的語句需要更改為:
if (queryCondition.CityNameList != null && queryCondition.CityNameList.Any()) { //這里需要循環嵌套 Join 來實現 foreach (string cityNameItem in queryCondition.CityNameList) { query = query.Join(_cityRepository.Table, p => p.CityID, c => c.Id, (p, c) => new { Person = p, City = c }) .Where(a => a.City.Name == cityNameItem) // 注意:這里不再是調用 .Contains 方法,而是直接等於判斷。 .Select(c => c.Person) .Distinct(); } } return query;
代碼解釋截圖如下(注意:.Select(c => c.Person) 后必須加一個 Distinct(),因為可能包含重復元素。):
基類方法如下:

4. 生成 的SQL 語句
SQL 語句如下:
SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[CityID] AS [CityID] FROM [dbo].[Person] AS [Extent1] INNER JOIN [dbo].[City] AS [Extent2] ON [Extent1].[CityID] = [Extent2].[Id] WHERE ( [Extent1].[Id] > 0 ) AND ( [Extent2].[Name] IN (N'深圳', N'北京') ) AND ( [Extent2].[Name] IS NOT NULL )
謝謝瀏覽!

