这是篇观察EF Core执行时行为的测试笔记,若有谬误繁请指正
model结构 => Song与SongRecord为一对多
public class Song: BaseField{ [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { set; get; } public string Name { set; get; } public string Descrption { set; get; } public virtual ICollection<SongRecord> SongRecords { set; get; } public Song() { this.SongRecords = new List<SongRecord>(); }}
public class SongRecord : BaseField{ [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { set; get; } [ForeignKey("Song")] public int SongId { set; get; } public DateTime Time { set; get; } public string Listener { set; get; } public string SongUrl { set; get; } public virtual Song Song { set; get; }}
1.消极式载入(Lazy loading)
1.1、若直接取回实体,由于消极式载入机制,其关联的SongRecords栏位为空
var lazy_q = Context.Songs;var lazy_m = lazy_q.ToList();
观察变数lazy_m:
1.2、变数lazy_m已是toList后的实体, SongRecords依旧为空
var lazy_child_t = lazy_m.SelectMany(x=>x.SongRecords).ToList();
观察变数lazy_child_t:
1.3、在这里使用到了 SongRecords栏位,则取回实体后, SongRecords栏位有值
var lazy_child_q = lazy_q.SelectMany(y => y.SongRecords);var lazy_child_m = lazy_child_q.ToList();
观察变数lazy_child_m:
1.4、执行到此,回头看上面的变数 lazy_m ,由于预设行为会进行tracking, 变数lazy_m侦测到变数 lazy_child_m 取回了 SongRecords 的资料,则其 SongRecords栏位会被填入值
观察变数lazy_m:
1.5、若不想进行tracking,则呼叫AsNoTracking()方法,取回的实体便是单纯的实体,不会发生(第1.4节)的行为
var lazy_m = lazy_q.AsNoTracking().ToList();
验证了官网描述,当呼叫了导览属性,才会从sql取回其资料
2.积极式载入(Eager loading)
指定 SongRecords栏位后取回实体,将一併取回包含 SongRecords栏位的所有资料
var eager_q = Context.Songs.Include(x => x.SongRecords);var eager_m = eager_q.ToList();
观察变数eager_m:
明确知道需要甚么资料时可以使用此模式,一次性取回资料,减少与资料库的往返次数
3.明确式载入(Explicit loading)
在明确需要实体时呼叫load(),以明确载入实体
var song = Context.Songs.FirstOrDefault();
观察变数song:
执行后,栏位 SongRecords的实体资料被填入,注意必须在tracking的状态才能使用load()
Context.Entry(song).Collection(x => x.SongRecords).Query().Load();
观察变数song: