【EF】2.主外键关系导航属性

一.数据准备
公司表Company和员工表Employee两张表创建主外键强关系,员工表Employee的Company_ID是公司表Company的外键,如下图所

二.解读主外键生成的实体特殊性

Company实体-主外键关系的话,EF生成的实体,主表Company实体有个子表Employee的集合,注意这个集合是virtual虚拟的

Employee实体-子表里面还有个主表Company的实例,引用属性,注意主表实体Company也是virtual虚拟的

三.导航属性是延迟查询

我们看到我们只查询公司ID是“0000000001”的公司,并没有主动去查询这个公司下面的员工并没有生成查询员工的sql,但是当我们遍历公司员工company.Employee的时候EF主动帮我们查询了得到这个公司下面的员工,所以证明导航属性是延迟查询,只有在真正使用的时候才去查询“0000000001”这个公司下面的员工,条件是virtaul属性(Employees是虚拟的)+ 默认配置(dbContext.Configuration.LazyLoadingEnabled = true;懒加载配置是true)

public class EFNavTest
{
    public static void Show()
    {
        {
            using (SchoolDBEntities dbContext = new SchoolDBEntities())
            {
                var companyList = dbContext.Set<Company>().Where(c => c.Company_ID == "0000000001");
                foreach (var company in companyList)//只查company
                {
                    Console.WriteLine(company.Company_Name);
                    foreach (var employee in company.Employees)
                    {
                        Console.WriteLine(employee.Employee_Name);
                    }
                }
                Console.Read();
            }
        }
    }
}

 

四.关闭延迟加载,子表的数据就没有了

dbContext.Configuration.LazyLoadingEnabled = false;

{
    using (SchoolDBEntities dbContext = new SchoolDBEntities())
    {
        dbContext.Configuration.LazyLoadingEnabled = false;//关闭延迟查询
        var companyList = dbContext.Set<Company>().Where(c => c.Company_Id == 02);
        foreach (var company in companyList)//只查company
        {
            Console.WriteLine(company.Company_Name);
            foreach (var employee in company.Employees)
            {
                Console.WriteLine(employee.Employee_Name);
            }
        }
    }
}

五.Include预先加载

预先加载,Include查询主表Company时就把子表数据Employee一次性查出来,和上面导航属性的懒加载不同,不同之处在于上面是当使用company.Employee的时候EF主动帮我们查询了得到这个公司下面的员工,而Include查询主表Company时就把子表数据Employee一次性查出来了不管你有没有用,我们从EF生成的sql语句就能看出来是个左外连接,它是把0000000001这个公司和它下面的员工一下都查询出来了

{
    //3、预先加载,Include查询主表时就把子表数据一次性查出来
    using (SchoolDBEntities dbContext = new SchoolDBEntities())
    {
        dbContext.Configuration.LazyLoadingEnabled = false;//是否关闭无所谓
        var companyList = dbContext.Set<Company>().Include("Employees").Where(c => c.Company_Id == "0000000001");
        foreach (var company in companyList)//只查company
        {
            Console.WriteLine(company.Company_Name);
            foreach (var employee in company.Employees)
{ Console.WriteLine(employee.Employee_Name);
} } } }

六.关闭延迟查询后,不想使用Include一次性查询子表的数据,只是需要子表的数据,才要查询,Collection可以显式加载

当执行了dbContext.Entry<Company>(company).Collection(c => c.Employees).Load();这句代码,就会生成查询该公司下的员工的sql语句,就会查询该公司的员工

 

{
    //4、关闭延迟查询后,如果需要子表数据,可以显示加载
    using (SchoolDBEntities dbContext = new SchoolDBEntities())
    {
        dbContext.Configuration.LazyLoadingEnabled = false;
        var companyList = dbContext.Set<Company>().Where(c => c.Company_Id == "0000000001");
        foreach (var company in companyList)//只查company
        {
             Console.WriteLine(company.Company_Name);
            dbContext.Entry<Company>(company).Collection(c => c.Employees).Load();
            foreach (var employee in company.Employees)
            {
                Console.WriteLine(employee.Employee_Name);
            }
        }
    }
}

 

七.关闭延迟查询后,如果需要主表数据,Reference可以显式加载

当执行了dbContext.Entry(employee).Reference(s => s.Company).Load();这句代码,就会生成查询该员工的公司的sql语句,就会查询该员工的公司

//5、关闭延迟查询后、如果需要主表数据,可以显示加载
using (SchoolDBEntities dbContext = new SchoolDBEntities())
{
    dbContext.Configuration.LazyLoadingEnabled = false;
    var employeeList = dbContext.Set<Employee>().Where(s => s.Employee_ID == "0000000001");
    foreach (var employee in employeeList)
    {
        Console.WriteLine(employee.Employee_Name);
        dbContext.Entry<Employee>(employee).Reference(s => s.Company).Load();
        string companyName = employee.Company.Company_Name;
        Console.WriteLine(companyName);
    }
}

八.结论

根据上面的阐述,可以表与表之间不必建立强关系,可以表与表非主外键关系建立导航属性,一般来说,主表有个子表的集合导航属性(像上述的public virtual ICollection<Employee> Employees { get; set; },注意必须是virtual虚拟的),子表里面还有个主表的实例(像上述的 public virtual Company Company { get; set; },注意必须是virtual虚拟的),引用属性,就可以了

posted @ 2020-02-03 18:14  David.Meng  阅读(1094)  评论(0编辑  收藏  举报