一、什么时候用导航属性
看数据库表的对应关系,一对多的时候用比较好,不用多写一个联表实体,而且查询高效
二、为实体配置导航属性
1.给关系是一的父表实体加上:
[FreeSql.DataAnnotations.Navigate(nameof(子表.子表关联字段))]
public List<子表> xxx { get; set; } = new List<子表>();
2.给关系是n的子表实体加上:
[FreeSql.DataAnnotations.Navigate(nameof(子表关联字段))]
public 父表 yyy { get; set; }
3.Demo例子:(一个省份对应多个城市)
/// <summary>
/// 1
/// </summary>
[Table("Province")]
public class Province
{
[FreeSql.DataAnnotations.Column(IsPrimary = true, IsIdentity = true, Name = "Id")]
public int Id { get; set; }
[Column("ProvinceCode")]
public int? ProvinceCode { get; set; }
[FreeSql.DataAnnotations.Navigate(nameof(City.ProvinceId))]
public List<City> citys { get; set; } = new List<City>();
}
/// <summary>
/// n
/// </summary>
[Table("City")]
public class City
{
[FreeSql.DataAnnotations.Column(IsPrimary = true, IsIdentity = true, Name = "Id")]
public int Id { get; set; }
[Column("CityCode")]
public int? CityCode { get; set; }
[Column("ProvinceId")]
public int ProvinceId { get; set; }
[Column("CityGroup")]
public int? CityGroup { get; set; }
[FreeSql.DataAnnotations.Navigate(nameof(ProvinceId))]
public Province province { get; set; }
}
三、怎么用导航属性
原理:左外连接
总结:使用关键字Include(找父表)、IncludeMany(找子表)
// 一对多导航属性关联查询
// 01 无条件查询
// 导航属性带出其父表(可序列化)
var list1 = MSfsql.Select<City>().Include(x => x.province).ToList();
// 导航属性带出其子表(不可序列化,因为子表含有父表字段,会一直引用下去)
var list2 = MSfsql.Select<Province>().IncludeMany(x => x.citys).ToList();
// 02 有条件查询
// 【子表 -> 父表】
var query1 = MSfsql.Select<City>().Where(x => (x.province.Id < 20) && (x.Id == 1 || x.Id == 198)) //先对本表(子表)筛选,条件可含子表 父表
.Include(x=>x.province) // 选择带出查询结果对应的那个父表
.ToList();
// 【父表->子表】
var query2 = MSfsql.Select<Province>()
.Where(x => x.Id < 20 && x.citys.Any(x=> x.Id ==1 || x.Id==198 )) //先对本表(父表)筛选,条件可含子表 父表
.IncludeMany(x => x.citys) // 选择带出查询结果对应的多个子表
.ToList();
var query3 = MSfsql.Select<Province>()
.Where(x => x.Id < 20 && x.citys.Any(x => x.Id == 1 || x.Id == 198)) //先对本表(父表)筛选,条件可含子表 父表
.IncludeMany(x => x.citys, then => then.Where(x=> x.CityGroup == 1)) // 选择带出子表,并且要求子表具备一定条件
.ToList();
四、一对多免导航属性配置的写法
1.实体
仅给关系是一的父表实体加上List<子表>字段即可
/// <summary>
/// 1
/// </summary>
[Table("Province")]
public class Province
{
[FreeSql.DataAnnotations.Column(IsPrimary = true, IsIdentity = true, Name = "Id")]
public int Id { get; set; }
[Column("ProvinceCode")]
public int? ProvinceCode { get; set; }
//[FreeSql.DataAnnotations.Navigate(nameof(City.ProvinceId))]
public List<City> citys { get; set; } = new List<City>();
}
/// <summary>
/// n
/// </summary>
[Table("City")]
public class City
{
[FreeSql.DataAnnotations.Column(IsPrimary = true, IsIdentity = true, Name = "Id")]
public int Id { get; set; }
[Column("CityCode")]
public int? CityCode { get; set; }
[Column("ProvinceId")]
public int ProvinceId { get; set; }
[Column("CityGroup")]
public int? CityGroup { get; set; }
// [FreeSql.DataAnnotations.Navigate(nameof(ProvinceId))]
// public Province province { get; set; }
}
2.查询方法
原理:先查满足条件的父表,提取出这些父表ID,再通过提取的父表ID查子表,freesql内部代码会通过IncludeMany里面的表达式树关联父表和子表
var query4 = fsql.Select<Province>()
.Where(x=>x.Id > 10) //此处写父表 or 子表的查询条件,筛选出父表
.IncludeMany(x => x.citys.Where(y => x.Id == y.ProvinceId)) //此处写关联条件,带出子表
.ToList();//本质是查两次,freesql内部有代码优化机制