C# “如何筛选”;包括「;实体框架中的实体?
实体:C# “如何筛选”;包括「;实体框架中的实体?,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,实体: public class Room { public Room() { this.Reservations = new HashSet<Reservation>(); } public int Id { get; set; } public decimal Rate { get; set; } public int HotelId {
public class Room
{
public Room()
{
this.Reservations = new HashSet<Reservation>();
}
public int Id { get; set; }
public decimal Rate { get; set; }
public int HotelId { get; set; }
public virtual Hotel Hotel { get; set; }
public virtual ICollection<Reservation> Reservations { get; set; }
}
public class Hotel
{
public Hotel()
{
this.Rooms = new HashSet<Room>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Room> 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<Hotel> Hotels { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<Room> Rooms { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Room>()
.HasKey(r => r.Id)
.HasRequired(r => r.Hotel)
.WithMany(r => r.Rooms)
.HasForeignKey(r => r.HotelId);
modelBuilder.Entity<Hotel>()
.HasKey(h => h.Id);
modelBuilder.Entity<Room>()
.HasMany(r => r.Reservations)
.WithRequired(r => r.Room)
.HasForeignKey(r => r.RoomId);
}
}
但我得到了一个例外:“DbIsOfExpression需要一个表达式参数,该参数具有与类型参数兼容的多态结果类型。”
现在,如果您注意到,我以两种不同的方式实现了它,第一种是通过显式加载相关实体,第二种是通过使用两个不同的查询,我的问题是,有没有一种方法可以加载我的对象图并过滤我“包含”的实体,只需从数据库执行一次行程
请注意,当前无法筛选加载了哪些相关实体。Include将始终引入所有相关实体
请求此功能
为了筛选子集合,您可以尝试选择要建模或匿名投影的子集合。
var anonymousProjection = dbContext.CustomerEntity
.Where(c => ! c.IsDeleted)
.Select(x=> new
{
customers = x,
orders = x.Orders.Where(h=>h.IsDeleted)
}).ToList();
过滤包含实体的方法有两种
- 使用投影(参见@Eldho答案)
- 使用第三方库
context.Entry(hotel)
.Collection(x => x.Rooms)
.Query()
.IncludeFilter(y => y.Reservations
.Where(z => z is ExecutiveSuite && z.Reservations.Any())
.Load();
在引擎盖下,库正好做了一个投影
维基:
编辑:回答子问题
你差点就成功了。房间已包含并过滤,但您没有包括预订
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();
编辑:回答评论 如何使用包含筛选器包含多级属性 您可以通过指定每个路径(每个IncludeFilter一个)来包括多级 因此
qry.Include(“Rooms.Hotel”)
成为:
qry.IncludeFilter(x => x.Rooms)
.IncludeFilter(x => x.Rooms.Select(y => y.Hotel))
编辑:回答评论 EF+是否支持dotnet 5.0
是的,它支持dotnet 5.0和EF Core 5.0。但是,对于IncludeFilter,您还应该直接在EF Core 5中查看过滤后的include内置:我正在考虑为这一点带来一个新的视角。 尽管这不能解决问题,但它可能会帮助您。 使用AutoMapper,您可以在将集合放入目标对象之前过滤它们。我已经设置了我的解决方案,在任何操作之前,所有内容都映射到DTO中,所以我使用AutoMapper作为这些内容的过滤器。
在这两个示例中,只有两个对数据库的查询。首先是酒店,然后是客房和预订。您还想要什么?为什么不在
include()
中包含所有内容?类似于:context.Hotels.Include(“房间.预订”)
?@sachin包括其他相关实体,然后尽可能使用到数据库的一次行程对这些相关实体进行筛选/排序。@haim770包括其他相关实体,然后尽可能使用到数据库的一次行程对这些相关实体进行筛选/排序。@RandelRamirez,请尝试并查看我所做的编辑,当我尝试在匿名对象中投影它时,我遇到了一个异常尝试一个强类型,如map to dto或viewmodel,就像这样我尝试在没有显式加载的情况下使用它,但似乎不起作用。=>context.hotels.IncludeFilter(h=>h.rooms.Where(x是ExecutiveSuite&&x.Reservations.Any())为什么会这样?我得到了一个不同的结果。我在用它吗correctly@RandelRamirez,我刚做了一个测试,一切似乎都正常。你得到了什么结果?此功能的一个限制是,以前加载的相关实体将始终包含在内(即使它不满足IncludeFilter谓词)。如果您愿意,还可以在我们的GitHub论坛上报告此问题,以使跟踪比使用堆栈溢出更容易:您所说的“不显式加载”是什么意思?您需要使用.Load()或.ToList()(或任何其他LINQ立即数方法)我这里有一个repo,如果您有时间,您可以查看它并看到我试图得到的结果。因为我可能错误地使用了你的api,所以不需要为bug提交文件。谢谢!:)项目名称为FilteringandOrderingRelatedEntities请告诉我新答案是否有效。我从我这边得到了同样的结果。可惜你没有包括一些示例代码。嗯,好吧,AutoMapper就是这样自动工作的。如果您使用ProjectTo(我个人的意见是,如果您要直接访问DB,您真的应该使用它),那么AutoMapper将生成底层表达式树,并对其进行解析。所以,当你在构建AutoMapper配置文件时,你基本上可以在那里“映射”它,然后你就去那里。它在基本的AutoMapper示例中进行了描述。
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();
qry.IncludeFilter(x => x.Rooms)
.IncludeFilter(x => x.Rooms.Select(y => y.Hotel))