1. 程式人生 > >Entity Framework DbSet<T>之Include方法與IQueryable<T>擴展方法Include的使用

Entity Framework DbSet<T>之Include方法與IQueryable<T>擴展方法Include的使用

work exp 這樣的 tin mapping oid role .cn expr

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();

技術分享

運行程序,如下:

技術分享

技術分享

Entity Framework DbSet<T>之Include方法與IQueryable<T>擴展方法Include的使用