如何在entity framework中过滤“包含”实体?

实体:

public class Room { public Room() { this.Reservations = new HashSet(); } public int Id { get; set; } public decimal Rate { get; set; } public int HotelId { get; set; } public virtual Hotel Hotel { get; set; } public virtual ICollection Reservations { get; set; } } public class Hotel { public Hotel() { this.Rooms = new HashSet(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection Rooms { get; set; } } public class Reservation { public int Id { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public string ContactName { get; set; } public int RoomId { get; set; } public virtual Room Room { get; set; } } public class ExecutiveSuite : Room { } public class DataContext : DbContext { public DbSet Hotels { get; set; } public DbSet Reservations { get; set; } public DbSet Rooms { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasKey(r => r.Id) .HasRequired(r => r.Hotel) .WithMany(r => r.Rooms) .HasForeignKey(r => r.HotelId); modelBuilder.Entity() .HasKey(h => h.Id); modelBuilder.Entity() .HasMany(r => r.Reservations) .WithRequired(r => r.Room) .HasForeignKey(r => r.RoomId); } } 

客户端代码(控制台应用程序):

 static void Main(string[] args) { // initialize and seed the database using (var context = new DataContext()) { var hotel = new Hotel { Name = "Grand Seasons Hotel" }; var r101 = new Room { Rate = 79.95M, Hotel = hotel }; var es201 = new ExecutiveSuite { Rate = 179.95M, Hotel = hotel }; var es301 = new ExecutiveSuite { Rate = 299.95M, Hotel = hotel }; var res1 = new Reservation { StartDate = DateTime.Parse("3/12/2010"), EndDate = DateTime.Parse("3/14/2010"), ContactName = "Roberta Jones", Room = es301 }; var res2 = new Reservation { StartDate = DateTime.Parse("1/18/2010"), EndDate = DateTime.Parse("1/28/2010"), ContactName = "Bill Meyers", Room = es301 }; var res3 = new Reservation { StartDate = DateTime.Parse("2/5/2010"), EndDate = DateTime.Parse("2/6/2010"), ContactName = "Robin Rosen", Room = r101 }; es301.Reservations.Add(res1); es301.Reservations.Add(res2); r101.Reservations.Add(res3); hotel.Rooms.Add(r101); hotel.Rooms.Add(es201); hotel.Rooms.Add(es301); context.Hotels.Add(hotel); context.SaveChanges(); } using (var context = new DataContext()) { context.Configuration.LazyLoadingEnabled = false; // Assume we have an instance of hotel var hotel = context.Hotels.First(); // Explicit loading with Load() provides opportunity to filter related data // obtained from the Include() method context.Entry(hotel) .Collection(x => x.Rooms) .Query() .Include(y => y.Reservations) .Where(y => y is ExecutiveSuite && y.Reservations.Any()) .Load(); Console.WriteLine("Executive Suites for {0} with reservations", hotel.Name); foreach (var room in hotel.Rooms) { Console.WriteLine("\nExecutive Suite {0} is {1} per night", room.Id, room.Rate.ToString("C")); Console.WriteLine("Current reservations are:"); foreach (var res in room.Reservations.OrderBy(r => r.StartDate)) { Console.WriteLine("\t{0} thru {1} ({2})", res.StartDate.ToShortDateString(), res.EndDate.ToShortDateString(), res.ContactName); } } } Console.WriteLine("Press  to continue..."); Console.ReadLine(); } using ( var context = new DataContext() ) { //context.Configuration.LazyLoadingEnabled = false; // Assume we have an instance of hotel var hotel = context.Hotels.First(); var rooms = context.Rooms.Include( r => r.Reservations ).Where( r => r is ExecutiveSuite && r.Reservations.Any() ).Where( r => r.Hotel.Id == hotel.Id ); Console.WriteLine( "Executive Suites for {0} with reservations", hotel.Name ); foreach ( var room in hotel.Rooms ) { Console.WriteLine( "\nExecutive Suite {0} is {1} per night", room.Id, room.Rate.ToString( "C" ) ); Console.WriteLine( "Current reservations are:" ); foreach ( var res in room.Reservations.OrderBy( r => r.StartDate ) ) { Console.WriteLine( "\t{0} thru {1} ({2})", res.StartDate.ToShortDateString(), res.EndDate.ToShortDateString(), res.ContactName ); } } } 

我尝试将其投影并放入匿名对象中:

  var hotel = context.Hotels.Select(h => new { Id = h.Id, Name = h.Name, Rooms = h.Rooms.Where(r => r.Reservations is ExecutiveSuite && r.Reservations.Any()) }).First(); 

但我得到一个例外:“DbIsOfExpression需要一个带有与type参数兼容的多态结果类型的表达式参数。”

现在,如果您注意到,我以两种不同的方式实现它,首先是通过显式加载相关实体,第二种是通过两个不同的查询,我的问题是,有没有办法可以加载我的对象图并过滤实体我“包括”只从数据库中一次旅行?

谢谢。

有两种方法可以过滤包含实体。

  • 使用投影(参见@Eldho答案)
  • 使用第三方库

免责声明 :我是项目Entity Framework Plus的所有者

EF + Query IncludeFilter允许轻松过滤包含的实体。

 context.Entry(hotel) .Collection(x => x.Rooms) .Query() .IncludeFilter(y => y.Reservations .Where(z => z is ExecutiveSuite && z.Reservations.Any()) .Load(); 

在引擎盖下,图书馆完全是一个投影。

Wiki: EF + Query包含filter

编辑 :回答子问题

你几乎做到了。 房间包括在内并过滤,但您没有包含预订。

 var hotel = context.Hotels // Include only executive suite with a reservation .IncludeFilter(x => x.Rooms.Where(y => y is ExecutiveSuite && y.Reservations.Any())) // Include only reservation from executive suite .IncludeFilter(x => x.Rooms.Where(y => y is ExecutiveSuite).Select(z => z.Reservations)) .First(); 

请注意,目前无法过滤加载了哪些相关实体。 包含将始终引入所有相关实体的Msdn引用

请在此处申请此function

为了过滤子集合,您可以尝试select模型或匿名投影。

 var anonymousProjection = dbContext.CustomerEntity .Where(c => ! c.IsDeleted) .Select(x=> new { customers = x, orders = x.Orders.Where(h=>h.IsDeleted) }).ToList(); 

类似的答案