Skip to content

Navigation query

shuxin edited this page Aug 21, 2024 · 12 revisions

导航属性

Chloe 除了支持连接查询外,还支持导航属性查询。

使用导航属性需先配置实体间关系,配置方法可以使用特性(Chloe.Annotations.NavigationAttribute)的方式,也可以使用 FluentMapping 的方式。

一对一导航:

List<Person> results = dbContext.Query<Person>().Include(a => a.City).ThenInclude(a => a.Province).ToList();

通过 Include 方法可以将关联的表内容(City,Province)查出来。

一对多导航:

List<Province> results = dbContext.Query<Province>().IncludeMany(a => a.Cities).ThenIncludeMany(a => a.Persons).ToList();

通过 IncludeMany 方法可以将关联的属性集合(Cities,Persons)查出来。

查询所有导航属性:

List<Province> results = dbContext.Query<Person>().IncludeAll().ToList();

通过 IncludeAll 方法可以将关联的所有属性查出来,避免了一个一个的调用 Include 或 IncludeMany 方法。

拆分查询(SplitQuery):

在导航属性 1:N 查询时,默认只生成一条包含多个 left join 的 sql 语句执行查询,如下:

List<Province> provinces = provinceQuery.IncludeAll().OrderBy(a => a.Id).ToList();
/*只会生成一条包含多个 left join 的 sql 语句
SELECT `T`.`Id`,`T`.`Name`,`T0`.`Id` AS `Id0`,`T0`.`Name` AS `Name0`,`T0`.`ProvinceId`,`T1`.`Name` AS `Name1`,`T1`.`Gender`,`T1`.`Age`,`T1`.`CityId`,`T1`.`CreateTime`,`T1`.`EditTime`,`T1`.`RowVersion`,`T1`.`Id` AS `Id1`,`T2`.`Id` AS `Id2`,`T2`.`IdNumber`,`T2`.`BirthDay`,`T3`.`Id` AS `Id3`,`T3`.`ProfileId`,`T3`.`FilePath` 
FROM `Province` AS `T` 
LEFT JOIN `City` AS `T0` ON `T`.`Id` = `T0`.`ProvinceId` 
LEFT JOIN `Person` AS `T1` ON `T0`.`Id` = `T1`.`CityId` 
INNER JOIN `PersonProfile` AS `T2` ON `T1`.`Id` = `T2`.`Id` 
LEFT JOIN `ProfileAnnex` AS `T3` ON `T2`.`Id` = `T3`.`ProfileId` 
ORDER BY `T`.`Id` ASC,`T0`.`Id` ASC,`T2`.`Id` ASC
*/

如上查询默认只会生成一条包含了多个 left join 的 sql 语句,假如关联的表多,数据一旦多起来,left join 的结果数据量会非常大,会严重影响查询效率。因此,可以使用拆分查询,如下:

//调用 SplitQuery 方法,会拆分生成多条查询语句
List<Province> provinces = provinceQuery.IncludeAll().SplitQuery().OrderBy(a => a.Id).ToList();
/*少量数据则会使用 in 查询
SELECT `T`.`Id`,`T`.`Name` FROM `Province` AS `T` ORDER BY `T`.`Id` ASC;

SELECT `T`.`Id`,`T`.`Name`,`T`.`ProvinceId` FROM `City` AS `T` WHERE `T`.`ProvinceId` IN (1,2,3,4,5);

SELECT `T`.`Name`,`T`.`Gender`,`T`.`Age`,`T`.`CityId`,`T`.`CreateTime`,`T`.`EditTime`,`T`.`RowVersion`,`T`.`Id`,`T0`.`Id` AS `Id0`,`T0`.`IdNumber`,`T0`.`BirthDay` 
FROM `Person` AS `T` 
INNER JOIN `PersonProfile` AS `T0` ON `T`.`Id` = `T0`.`Id` 
WHERE `T`.`CityId` IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14);

SELECT `T`.`Id`,`T`.`ProfileId`,`T`.`FilePath` 
FROM `ProfileAnnex` AS `T` 
WHERE `T`.`ProfileId` IN (1,2,3,4,5,6,7,8,9,10,...);
*/

/*如果查询的数据数量过多,会生成多表 inner join 查询
SELECT `T`.`Id`,`T`.`Name` FROM `Province` AS `T` ORDER BY `T`.`Id` ASC;

SELECT `T0`.`Id`,`T0`.`Name`,`T0`.`ProvinceId` FROM `Province` AS `T` INNER JOIN `City` AS `T0` ON `T`.`Id` = `T0`.`ProvinceId`;

SELECT `T1`.`Name`,`T1`.`Gender`,`T1`.`Age`,`T1`.`CityId`,`T1`.`CreateTime`,`T1`.`EditTime`,`T1`.`RowVersion`,`T1`.`Id`,`T2`.`Id` AS `Id0`,`T2`.`IdNumber`,`T2`.`BirthDay` 
FROM `Province` AS `T` 
INNER JOIN `City` AS `T0` ON `T`.`Id` = `T0`.`ProvinceId` 
INNER JOIN `Person` AS `T1` ON `T0`.`Id` = `T1`.`CityId` 
INNER JOIN `PersonProfile` AS `T2` ON `T1`.`Id` = `T2`.`Id`;

SELECT `T3`.`Id`,`T3`.`ProfileId`,`T3`.`FilePath` 
FROM `Province` AS `T` 
INNER JOIN `City` AS `T0` ON `T`.`Id` = `T0`.`ProvinceId` 
INNER JOIN `Person` AS `T1` ON `T0`.`Id` = `T1`.`CityId` 
INNER JOIN `PersonProfile` AS `T2` ON `T1`.`Id` = `T2`.`Id` 
INNER JOIN `ProfileAnnex` AS `T3` ON `T2`.`Id` = `T3`.`ProfileId`;
*/

更详细用法请参考 github 上的 demo