zoukankan      html  css  js  c++  java
  • 关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明

    一、首先了解下Entity Framework 自动关联查询:

    Entity Framework 自动关联查询,有三种方法:Lazy Loading(延迟加载),Eager Loading(预先加载),Explicit Loading(显式加载),其中Lazy Loading和Explicit Loading都是延迟加载。

    (注:由于Entity Framework版本的不同,以及采用不同的模式(DB First,Model First,Code First)来构建的Entity,最终导致可能自动关联查询的方法也有所不同,本文中的示例代码均以Entity Framework 6.0,且采用Code First模式来构建的Entity为基础)

    一、Lazy Loading(延迟加载):这是默认情况(默认实体上下文对象的属性:Configuration.LazyLoadingEnabled=true,若该属性设为false则无效),若实体类型包含其它实体类型(POCO类)的属性(也可称为导航属性),且同时满足如下条件即可实列延迟加载,

    1.该属性的类型必需为public且不能为Sealed;

    2.属性标记为Virtual

    作用:在您访问导航属性时,会从数据源自动加载相关实体,若实体尚未在 实体上下文对象中,则您访问的每个导航属性都会导致针对数据源执行一个单独的查询。

    示例代码如下:

        [Table("User",Schema="dbo")]
        public class User
        {
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            [Display(Name = "用户ID")]
            public int ID { get; set; }
    
            [Required]
            [MinLength(6)]
            [MaxLength(15)]
            [Unique("User", "UserName")]
            [Display(Name = "用户名")]
            public string UserName { get; set; }
    
            [Required]
            [Display(Name = "密码")]
            public string Password { get; set; }
    
            [Required]
            [Display(Name = "用户类型")]
            public int UserTypeID { get; set; }
    
            [ForeignKey("UserTypeID")]
            public virtual UserType UserType { get; set; } //此属性在查询User时,会自动依据UserTypeID 关联查旬UserType ,并将结果赋值给UserType 属性
        }
    

    二、Eager Loading(预先加载):在LazyLoadingEnabled设为false或导航属性没有使用Virtual的情况下,使用IQueryable的扩展方法Include指定预先加载关联的实体。

    作用:Include方法中的查询路径指定将哪些相关实体作为初始查询的一部分返回,当在查询语句中定义了Include查询路径,查询时仅需对数据库请求一次,即可在单个结果集中返回查询路径所定义的所有实体。

    示例代码如下:

    var entitiesContext=new TEMSContext();
    entitiesContext.Configuration.LazyLoadingEnabled=false;
    var users = entitiesContext.Users.Include("UserType");
    //var users = entitiesContext.Set<User>().Include("UserType");与上面语句相同
    Assert.AreNotEqual(null, users.First().UserType);

    三、Explicit Loading(显式加载):在LazyLoadingEnabled设为false或导航属性没有使用Virtual的情况下,使用DbEntityEntry.Reference方法来显式加载指定导航属性的单个值,DbEntityEntry.Collection方法来显式加载指定导航属性的值集合,若采用DB First时,可使用ObjectContext.LoadProperty方法来显式加载指定导航属性。

    作用:查询时并不会从数据库查询并加载导航属性的值,仅当使用Reference或Collection方法来指定导航属性,并调用Load方法时或调用ObjectContext.LoadProperty,才会从数据库查询数据并赋值给指定的导航属性,若查询的结果集较多时,可能会出现多次往返查询数据。

    示例代码如下:

    //这是Code First模式下显式加载数据
    var entitiesContext = new TEMSContext();
                entitiesContext.Configuration.LazyLoadingEnabled = false;
                var user = entitiesContext.Users.First();
                var u = entitiesContext.Entry(user);
                u.Reference(t => t.UserType).Load();
                Assert.AreNotEqual(null, user.UserType);
    
    //这是DB First模式下显示式加载数据
    var db = new aTestEntities();
                db.ContextOptions.LazyLoadingEnabled = false;
                var comp = db.Companies.First();
                db.LoadProperty(comp, t => t.Departments);
                Assert.AreNotEqual(0, comp.Departments.Count);
    

    二、自动关联更新导航属性对应的实体注意事项说明

    若开启了Lazy Loading(延迟加载)模式,即满足上面第一种关联查询条件时,在执行实体新增的时,需注意:如果直接赋值给导航属性,则当提交到数据库时,会自动关联新增导航属性对应的表记录,不论你是否在实体中有指定导航属性对应的外键属性的值,仍会以关联新增导航属性对应的表记录后更新该外键属性的值,可能表达有点不清楚,请看下面的示例:

    var entitiesContext = new TEMSContext();
    User user = new User() {UserName="testuser",RealName="测试账号",CompanyID = 1, Company = UserBusiness.CurrentUser.Company };
    entitiesContext.Users.Add(user);
    entitiesContext.SaveChanges();
    

     以上代码中,CompanyID为导航属性Company的外键属性,我这里直接将两个属性都赋值了,Company的ID也是1(Company表中存在ID为1的记录),UserBusiness.CurrentUser为我系统当前登录的用户,按理讲,执行新增后,应该只会在User表中新增一条记录,而实际却是先在Company表中新增一条记录(忽略指定的主键,即:ID=1),并将返回的新ID赋值给CompanyID(比如为2),然后再在User表中新增一条记录,最终形成User.CompanyID=2,而不是1,这个问题也是困扰我好几天了,也没有找到根本原因,目前的解决办法是只赋值外键属性CompanyID,而导航属性Company则不赋值,这样在保存时就不会出错了。如果大家知道原因还请告之,非常感谢!

    来自:zuowj.cnblogs.com

  • 相关阅读:
    云计算初探
    MySQL、HBase、ES的特点和区别
    MongoDB、ElasticSearch、Redis、HBase这四种热门数据库的优缺点及应用场景
    主流 Kubernetes 发行版梳理
    如何在flink中传递参数
    (47)zabbix报警媒介:Ez Texting
    (46)zabbix报警媒介:Jabber
    (45)zabbix报警媒介:SMS
    (44)zabbix报警媒介:email
    (43)zabbix报警媒介介绍
  • 原文地址:https://www.cnblogs.com/zuowj/p/4514230.html
Copyright © 2011-2022 走看看