• Entity Framework DbSet<T>之Include方法与IQueryable<T>扩展方法Include的使用


    Entity Framework使用Code First方式时,实体之间已经配置好关系,根据实际情况某些情况下需要同时获取导航属性,比如获取商品的同时需要获取分类属性(导航属性),或者基于优化方面考虑等,下面来看一个例子

    例子中有会员实体类(Member)与角色实体类(Role),Role与Member的关系是1:n,控制台应用程序代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Data.Entity;
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                EFContext<Member> efMemberContext = new EFContext<Member>();
                var members = efMemberContext.Set<Member>().ToList();
                foreach (Member item in members)
                {
                    Console.WriteLine(item.Role.Name);
                }
                Console.ReadKey();
            }
        }
    }
    EFContext类、Member类、Role类以及Mapping类如下:
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Linq.Expressions;
    
    namespace ConsoleApplication2
    {
        public partial class EFContext<T> : DbContext where T : class
        {
            public EFContext(): base("name=MyConnectionString")
            {
            }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                Database.SetInitializer<EFContext<T>> (null);
                modelBuilder.Configurations.Add(new MemberMap());
                modelBuilder.Configurations.Add(new RoleMap());
                base.OnModelCreating(modelBuilder);
            }
    
            
            public DbSet<T> Table { get; set; }
    
            public IQueryable<T> GetList(Expression<Func<T,bool>> where)
            {
                return this.Table.Where(where);
            }
        }
    }
    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
        public partial class Member
        {
            public int Id { get; set; }
    
            public string Name { get; set; }
    
            public string Password { get; set; }
    
            public bool Delete{ get; set; }
    
            public int RoleId { get; set; }
    
            public virtual Role Role { get; set; }
        }
    }
    View Code
    using System;
    using System.Collections.Generic;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
        public class MemberMap : EntityTypeConfiguration<Member>
        {
            public MemberMap()
            {
                this.ToTable("Member");
                this.HasKey(m => m.Id);
                this.HasRequired(m => m.Role).WithMany(r => r.Members).HasForeignKey(m => m.RoleId);
            }
        }
    }
    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
        public partial class Role
        {
            public int Id { get; set; }
    
            public string Name { get; set; }
    
            public virtual ICollection<Member> Members { get; set; }
        }
    }
    View Code
    using System;
    using System.Collections.Generic;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
        public class RoleMap: EntityTypeConfiguration<Role>
        {
            public RoleMap()
            {
                this.ToTable("Role");
                this.HasKey(r => r.Id);
            }
        }
    }
    View Code

    数据库中现有数据如下:

     

     

    运行程序 ,在SQL Profiler中看到生成了如下的语句:

    1. 执行efMemberContext.DbSet<Member>().ToList();生成的SQL:

     

    2. foreach循环了五次,每次生成一条SQL,如下:

    这里省略描述了其中三条SQL,SQL语句类似,只是读取Role属性时根据不同的RoleId获取信息,所以只是参数值 不同

    从上面的例子可以看出循环几次为了获取导航属性而生成了几条SQL,如果数据库里表有数据量很大,这样的方式对性能的影响可想而知。 根据上面的例子,现在想有没有一种方法在获取Member的同时获取Role信息,也就是生成的SQL是两个表inner join ,于是Include就发挥了作用了。改写Main()方法中的代码如下:

    var members = efMemberContext.Set<Member>().Include("Role").ToList();

    上面是获取Member时同时获取导航属性Role信息,这样在生成SQL里就是inner join ,再次运行程序,这里可以看到,在SQL Profiler中只执行了一次SQL,而SQL是带inner join的形式 

    上面两种方式的控制台输出如下:

     

    这里可能有人会有疑问了,如里EF通用类封装了没有公开DbSet<T>类型的属性或者只有IQueryable<T>类型的返回,又或者DbSet<T>().Where(e => true)之后再想Include怎么办?

    如果是使用Entity Framework,System.Data.Entity.QueryableExtensions类封装了IIQueryable<T>的扩展方法,其中有Include扩展方法,引用命名空间System.Data.Entity可以使用。

    下面是获取RoleId<5的会员信息与对应的角色信息:

    EFContext<Member> efMemberContext = new EFContext<Member>();
    var members = efMemberContext.Set<Member>().Where(m =>m.RoleId < 5).Include("Role").ToList();
    foreach (Member item in members)
    {
        Console.WriteLine("{0}:{1}",item.Name,item.Role.Name);
    }
    Console.ReadKey();

     

     运行程序,如下:

     

     

     

  • 相关阅读:
    我业余时间开发的东西文本编辑器 美丽的控件
    讲讲语言转换程序:将一种语言转换为另一种语言的程序
    调整心态,正确应对所学技术的失宠?(至F#,SL的学习者们)
    开贴说说文本编辑器的那些事情捕获输入内容
    开贴说说文本编辑器的那些事情 字符串的宽度
    电话亭。
    【旅行】西湖——初秋。
    偶这个前端设计师有生以来写过的最复杂的程序业务逻辑(菜鸟贴)。
    “页面制作人员”?“页面工程师”?“页面架构师”?滚一边去!
    【旅行】生的活力——西塘正午。
  • 原文地址:https://www.cnblogs.com/godbell/p/7348411.html
Copyright © 2020-2023  润新知