• EF5.x Code First 表关联与贪婪加载、延迟加载


    晚上体验了一把EF的对象关联,确实强悍!

    EF数据库对象的外键管理方式

    1-指定导航属性,会自动生成外键,命名规则为:“表名_主键名”
    2-默认情况下与导航属性的主键名称相同的字段会自动被标记为外键
    3-通过[ForeignKey]标记指定实体类的属性为外键,
    4-方式2的升级版,与导航属性的主键名称相同的字段会自动被标记为外键,然后指定字段对应的数据库中的列名

    案例:

    组织架构n : 1【组织用户关联】1 :n用户

    using System;
    /**
     * 作者:陈杰
     * 时间:2012-08-10 00:25
     * 功能:公共字段接口
     **/
    namespace ElegantWM.EntityModel
    {
        public interface IEntity
        {
            Guid Id { get; set; }
    
            string CreateUser { get; set; }
            DateTime CreateTime { get; set; }
            string ModifyUser { get; set; }
            DateTime? ModifyTime { get; set; }
            Byte[] RowVersion { get; set; }
        }
    }
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    /**
     * 作者:陈杰
     * 时间:2012-08-10 00:25
     * 功能:公共字段接口实现类
     **/
    namespace ElegantWM.EntityModel
    {
        public class Entity:IEntity
        {
            public Guid Id { get; set; }
    
            public string CreateUser { get; set; }
            public DateTime CreateTime { get; set; }
            public string ModifyUser { get; set; }
            public DateTime? ModifyTime { get; set; }
            [Timestamp]
            public Byte[] RowVersion { get; set; }
        }
    }

    以上两个类为数据库实体的公共属性,但随着业务的复杂度增加,感觉提取实体的公共字段并不是很妥当,可适当折中考虑。

    /*  组织架构实体  */
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ElegantWM.EntityModel
    {
        public class WMS_Org : Entity
        {
            public WMS_Org() { }
    
            public string OrgName { get; set; }
            public string OrgDesc { get; set; }
            public int OrgOrder { get; set; }
            public string OrgFatherId { get; set; }
            public virtual ICollection<WMS_OrgUser> OrgUserIds { get; set; }
        }
    }
    /*  用户实体  */
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ElegantWM.EntityModel
    {
        public class WMS_User : Entity
        {
            public WMS_User() { }
    
            public string UserName { get; set; }
            public string NickName { get; set; }
            public string UserPwd { get; set; }
            public string Sex { get; set; }
            public string Phone { get; set; }
            public string Email { get; set; }
            public string QQ { get; set; }
            public string Address { get; set; }
            public string Remark { get; set; }
            public virtual ICollection<WMS_OrgUser> UserOrgIds { get; set; }
        }
    }
    /* 用户和组织架构的关系 */
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Text;
    
    namespace ElegantWM.EntityModel
    {
        public class WMS_OrgUser : Entity
        {
            public WMS_OrgUser() { }
    //3. 指定外键的方式
            public Guid OrgId { get; set; }
            [ForeignKey("OrgId")]
            public virtual WMS_Org Org { get; set; }
    
            public Guid UserId { get; set; }
            [ForeignKey("UserId")]
            public virtual WMS_User User { get; set; }
    
    //1. 不指定外键,EF默认会生成 对象_表对象ID,也就是Org_Id,User_Id
            public virtual WMS_Org Org { get; set; }
            public virtual WMS_User User { get; set; }
        }
    
    //2. 不适合本案例,因为所有对象的主键都是ID,自动识别
            public Guid Id { get; set; }
            public virtual WMS_Org Org { get; set; }
            ......
    //4. 指定数据库真实外键名称
            [Column("OrgID")]
            public Guid Id { get; set; }
            public virtual WMS_Org Org { get; set; }
    }
                    

    根据上面的4个原则,可以在组合出符合自己实际业务的关联类。

    建立好了关联类后,需要注意的是,数据库中外键类型必须和主表的主键类型一致,当然外键关系你可以不用强制建立,但类型必须一直,否则会出错。

    关联的对象注意声明为virtual,以供延迟加载。

    当 EF 访问实体的子实体的时候是如何工作的呢?你的集合是 POCO 的集合,所以,在访问的时候没有事件发生,EF 通过从你定义的实体派生一个动态的对象,然后覆盖你的子实体集合访问属性来实现。这就是为什么需要标记你的子实体集合属性为 virtual 的原因。

    执行EF的操作,验证
    //1.创建关系
    WMS_OrgUser ou = new WMS_OrgUser();
                ou.OrgId = Guid.Parse("79DDB55A-1587-4928-A312-58DA0C091459");
                ou.UserId = Guid.Parse("9E99FBCF-1517-4ACA-A81D-AE3535AF8E37");
                WMFactory.WMSOrgUser.Insert(ou);
    
    //2. 根据关系,已知组织ID,获取用户
                WMS_OrgUser orguser = WMFactory.WMSOrgUser.GetById("7E632B62-B8EC-4D58-AE94-A412868146E7");
    //正常获取了用户对象,正常打印用户昵称
                string name = orguser.User.NickName;
    //3.测试贪婪加载,见文章后面
                orguser = WMFactory.WMSOrgUser.TestNoLazyLoading(Guid.Parse("7E632B62-B8EC-4D58-AE94-A412868146E7"));
    
    //4.获取组织架构下的用户
                WMS_Org org = WMFactory.WMSOrg.GetById("79DDB55A-1587-4928-A312-58DA0C091459");
                ICollection<WMS_OrgUser> coll = org.OrgUserIds;
                orguser = coll.ToList()[0];
                string orguserid=orguser.Id.ToString();
                string orgusername = orguser.User.NickName;
    关于延迟加载和贪婪加载

    1.延迟加载,当对象使用的时候,再去数据库中加载,例如上面的orguser.User,当我调用这句话的时候,EF会到数据库中加载数据

    EF默认是开启延迟加载的,禁用如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.ModelConfiguration.Conventions;
    using ElegantWM.EntityModel;
    using System.Configuration;
    /**
     * 作者:陈杰
     * QQ:710782046
     * 时间:2012-08-10
     * 功能:EF配置文件,支持多数据库
     **/
    namespace ElegantWM.DAL
    {
        public class DB : DbContext
        {
            //public static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    
            //配置连接串,默认数据库DefaultDB
            public DB(string _ConnectStr)
                : base()
            {
                Database.Connection.ConnectionString = ConfigurationManager.ConnectionStrings[_ConnectStr].ToString();
                Database.SetInitializer<DB>(null);
    //这里哦
    this.Configuration.LazyLoadingEnabled = false; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //已经存在的数据库,不然会出现负数 modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); base.OnModelCreating(modelBuilder); } //注册到EF public DbSet<WMS_Role> wmRole { get; set; } public DbSet<WMS_User> wmUser { get; set; } public DbSet<WMS_Org> wmOrg { get; set; } public DbSet<WMS_Module> wmModule { get; set; } public DbSet<WMS_RoleModule> wmRoleModule { get; set; } public DbSet<WMS_UserRole> wmUserRole { get; set; } public DbSet<WMS_OrgUser> wmsOrgUser { get; set; } } }

    2.贪懒加载,一次性把数据组织好,加载到内存,类似join表

    例如以上案例4,通过组织架构获取用户,EF延迟加载执行的sql如下:

    exec sp_executesql N'SELECT TOP (2) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[OrgName] AS [OrgName], 
    [Extent1].[OrgDesc] AS [OrgDesc], 
    [Extent1].[OrgOrder] AS [OrgOrder], 
    [Extent1].[OrgFatherId] AS [OrgFatherId], 
    [Extent1].[CreateUser] AS [CreateUser], 
    [Extent1].[CreateTime] AS [CreateTime], 
    [Extent1].[ModifyUser] AS [ModifyUser], 
    [Extent1].[ModifyTime] AS [ModifyTime], 
    [Extent1].[RowVersion] AS [RowVersion]
    FROM [dbo].[WMS_Org] AS [Extent1]
    WHERE [Extent1].[Id] = @p__linq__0',N'@p__linq__0 uniqueidentifier',@p__linq__0='79DDB55A-1587-4928-A312-58DA0C091459'
    
    
    
    exec sp_executesql N'SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[OrgId] AS [OrgId], 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[CreateUser] AS [CreateUser], 
    [Extent1].[CreateTime] AS [CreateTime], 
    [Extent1].[ModifyUser] AS [ModifyUser], 
    [Extent1].[ModifyTime] AS [ModifyTime], 
    [Extent1].[RowVersion] AS [RowVersion]
    FROM [dbo].[WMS_OrgUser] AS [Extent1]
    WHERE [Extent1].[OrgId] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='79DDB55A-1587-4928-A312-58DA0C091459'
    
    
    
    exec sp_executesql N'SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[UserName] AS [UserName], 
    [Extent1].[NickName] AS [NickName], 
    [Extent1].[UserPwd] AS [UserPwd], 
    [Extent1].[Sex] AS [Sex], 
    [Extent1].[Phone] AS [Phone], 
    [Extent1].[Email] AS [Email], 
    [Extent1].[QQ] AS [QQ], 
    [Extent1].[Address] AS [Address], 
    [Extent1].[Remark] AS [Remark], 
    [Extent1].[CreateUser] AS [CreateUser], 
    [Extent1].[CreateTime] AS [CreateTime], 
    [Extent1].[ModifyUser] AS [ModifyUser], 
    [Extent1].[ModifyTime] AS [ModifyTime], 
    [Extent1].[RowVersion] AS [RowVersion]
    FROM [dbo].[WMS_User] AS [Extent1]
    WHERE [Extent1].[Id] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='9D001F8D-E304-4DB3-B5C0-7C5139E888A6'

    贪婪加载的方式,如测试3,产生的SQL如下:

     public WMS_OrgUser TestNoLazyLoading(Guid id)
            {
                return DBSET.Include("User").Include("Org").FirstOrDefault(o => o.Id == id);
            }
    exec sp_executesql N'SELECT 
    1 AS [C1], 
    [Limit1].[Id] AS [Id], 
    [Limit1].[OrgId] AS [OrgId], 
    [Limit1].[UserId] AS [UserId], 
    [Limit1].[CreateUser] AS [CreateUser], 
    [Limit1].[CreateTime] AS [CreateTime], 
    [Limit1].[ModifyUser] AS [ModifyUser], 
    [Limit1].[ModifyTime] AS [ModifyTime], 
    [Limit1].[RowVersion] AS [RowVersion], 
    [Extent2].[Id] AS [Id1], 
    [Extent2].[UserName] AS [UserName], 
    [Extent2].[NickName] AS [NickName], 
    [Extent2].[UserPwd] AS [UserPwd], 
    [Extent2].[Sex] AS [Sex], 
    [Extent2].[Phone] AS [Phone], 
    [Extent2].[Email] AS [Email], 
    [Extent2].[QQ] AS [QQ], 
    [Extent2].[Address] AS [Address], 
    [Extent2].[Remark] AS [Remark], 
    [Extent2].[CreateUser] AS [CreateUser1], 
    [Extent2].[CreateTime] AS [CreateTime1], 
    [Extent2].[ModifyUser] AS [ModifyUser1], 
    [Extent2].[ModifyTime] AS [ModifyTime1], 
    [Extent2].[RowVersion] AS [RowVersion1], 
    [Extent3].[Id] AS [Id2], 
    [Extent3].[OrgName] AS [OrgName], 
    [Extent3].[OrgDesc] AS [OrgDesc], 
    [Extent3].[OrgOrder] AS [OrgOrder], 
    [Extent3].[OrgFatherId] AS [OrgFatherId], 
    [Extent3].[CreateUser] AS [CreateUser2], 
    [Extent3].[CreateTime] AS [CreateTime2], 
    [Extent3].[ModifyUser] AS [ModifyUser2], 
    [Extent3].[ModifyTime] AS [ModifyTime2], 
    [Extent3].[RowVersion] AS [RowVersion2]
    FROM    (SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[OrgId] AS [OrgId], [Extent1].[UserId] AS [UserId], [Extent1].[CreateUser] AS [CreateUser], [Extent1].[CreateTime] AS [CreateTime], [Extent1].[ModifyUser] AS [ModifyUser], [Extent1].[ModifyTime] AS [ModifyTime], [Extent1].[RowVersion] AS [RowVersion]
        FROM [dbo].[WMS_OrgUser] AS [Extent1]
        WHERE [Extent1].[Id] = @p__linq__0 ) AS [Limit1]
    LEFT OUTER JOIN [dbo].[WMS_User] AS [Extent2] ON [Limit1].[UserId] = [Extent2].[Id]
    LEFT OUTER JOIN [dbo].[WMS_Org] AS [Extent3] ON [Limit1].[OrgId] = [Extent3].[Id]',N'@p__linq__0 uniqueidentifier',@p__linq__0='7E632B62-B8EC-4D58-AE94-A412868146E7'

    两种方式各有各的好处,可以根据具体情况使用

  • 相关阅读:
    Anoconda管理Python版本 | Python
    VSCode用以Python开发的配置 | VSCode
    不联网的情况下安装python环境 | Python(转)
    批量按要求修改文件名
    [OpenLayers] 控件系列之SelectFeature同时支持hover与click
    python使用suds调用webservice接口
    【转载】eMBMS知识点汇总(概念/应用场景/工作原理/标准进程/发展现状)
    处理器分类
    3GPP Release 4G-5G 演进
    浅谈css中一个元素如何在其父元素居中显示
  • 原文地址:https://www.cnblogs.com/qidian10/p/3114383.html
Copyright © 2020-2023  润新知