[英]Entity Framework `Include` for nested navigation properties results in more data than expected
private IQueryable<MyEntity> GetEntities(MyDataContext dc)
{
return dc.MyEntities.Include(
entity => entity.RelationalEntities.Select(
relationalEntity => relationalEntity.ChildEntities
)
);
}
At a glance, this appears correct.乍一看,这似乎是正确的。
However, after taking a closer look at the data returned, we find that ChildEntities
incorrectly contains a collection of all relations in the relational table, even though it should only contain ChildEntity
entries that relate to the entity
object referred to by the RelationalEntity
table.然而,在仔细查看返回的数据后,我们发现
ChildEntities
错误地包含了关系表中所有关系的集合,尽管它应该只包含与RelationalEntity
表引用的entity
object 相关的ChildEntity
条目。
To put it simply, we are getting more ChildEntity
entries than expected from this query, and there does not appear to be a way to filter on them by using .Where()
in these .Include()
calls due to framework limitations.简而言之,我们从这个查询中获得了比预期更多的
ChildEntity
条目,并且由于框架限制,似乎没有办法通过在这些.Include()
调用中使用.Where()
来过滤它们。
Ideally, I would be able to extend the query as follows, but this code results in Entity Framework exceptions:理想情况下,我可以按如下方式扩展查询,但此代码会导致实体框架异常:
private IQueryable<MyEntity> GetEntities(RcmEntities dc)
{
return dc.MyEntities.Include(
entity => entity.RelationalEntity.Select(
relationalEntity => relationalEntity.ChildEntities.Where(
childEntity => childEntity.MyEntityId == entity.MyEntityId
&& childEntity.ChildEntityId == relationalEntity.ChildEntityId
)
)
);
}
The table relation looks something like this:表关系如下所示:
MyEntity.MyEntityId -> RelationalEntity.MyEntityId, RelationalEntity.ChildEntityId -> ChildEntity.ChildEntityId
How can I adjust this Entity Framework query to only return ChildEntity
entries that relate to the referred MyEntity
entry?如何调整此实体框架查询以仅返回与引用的
MyEntity
条目相关的ChildEntity
条目?
Edit 1:编辑1:
By request, here is an exact copy of our entity classes, with all domain-specific information removed:根据要求,这里是我们实体类的精确副本,删除了所有特定于域的信息:
namespace TransportTypes
{
using Newtonsoft.Json;
// Entity
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class Entity
{
public int EntityId { get; set; } // EntityId (Primary key)
// Removed domain-specific fields...
// Reverse navigation
/// <summary>
/// Child ChildEntitys (Many-to-Many) mapped by table [EntityEnabledChild]
/// </summary>
[JsonIgnore]
public virtual System.Collections.Generic.ICollection<ChildEntity> ChildEntitys { get; set; } = new System.Collections.Generic.List<ChildEntity>(); // Many to many mapping
/// <summary>
/// Child ChildEntityContents where [ChildEntityContent].[EntityId] point to this entity (FK_ChildEntityContent_Entity)
/// </summary>
[JsonIgnore]
public virtual System.Collections.Generic.ICollection<ChildEntityContent> ChildEntityContents { get; set; } = new System.Collections.Generic.List<ChildEntityContent>(); // ChildEntityContent.FK_ChildEntityContent_Entity
}
// Entity
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class EntityConfiguration : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Entity>
{
public EntityConfiguration()
: this("dbo")
{
}
public EntityConfiguration(string schema)
{
ToTable("Entity", schema);
HasKey(x => x.EntityId);
Property(x => x.EntityId).HasColumnName(@"EntityId").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
HasMany(t => t.ChildEntitys).WithMany(t => t.Entitys).Map(m =>
{
m.ToTable("EntityEnabledChild", "dbo");
m.MapLeftKey("EntityId");
m.MapRightKey("ChildEntityId");
});
InitializePartial();
}
partial void InitializePartial();
}
// ChildEntity
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class ChildEntity
{
public int ChildEntityId { get; set; } // ChildEntityId (Primary key)
// Reverse navigation
/// <summary>
/// Child Entitys (Many-to-Many) mapped by table [EntityEnabledChild]
/// </summary>
[JsonIgnore]
public virtual System.Collections.Generic.ICollection<Entity> Entitys { get; set; } = new System.Collections.Generic.List<Entity>(); // Many to many mapping
/// <summary>
/// Child ChildEntityContents where [ChildEntityContent].[ChildEntityId] point to this entity (FK_ChildEntityContent_ChildEntity)
/// </summary>
[JsonIgnore]
public virtual System.Collections.Generic.ICollection<ChildEntityContent> ChildEntityContents { get; set; } = new System.Collections.Generic.List<ChildEntityContent>(); // ChildEntityContent.FK_ChildEntityContent_ChildEntity
}
// ChildEntity
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class ChildEntityConfiguration : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<ChildEntity>
{
public ChildEntityConfiguration()
: this("dbo")
{
}
public ChildEntityConfiguration(string schema)
{
ToTable("ChildEntity", schema);
HasKey(x => x.ChildEntityId);
Property(x => x.ChildEntityId).HasColumnName(@"ChildEntityId").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
InitializePartial();
}
partial void InitializePartial();
}
// ChildEntityContent
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class ChildEntityContent
{
public int EntityId { get; set; } // EntityId (Primary key)
public int ChildEntityId { get; set; } // ChildEntityId (Primary key)
public string ContentKey { get; set; } // ContentKey (Primary key) (length: 100)
public string ContentValue { get; set; } // ContentValue
// Foreign keys
/// <summary>
/// Parent Entity pointed by [ChildEntityContent].([EntityId]) (FK_ChildEntityContent_Entity)
/// </summary>
[JsonIgnore]
public virtual Entity Entity { get; set; } // FK_ChildEntityContent_Entity
/// <summary>
/// Parent ChildEntity pointed by [ChildEntityContent].([ChildEntityId]) (FK_ChildEntityContent_ChildEntity)
/// </summary>
[JsonIgnore]
public virtual ChildEntity ChildEntity { get; set; } // FK_ChildEntityContent_ChildEntity
}
// ChildEntityContent
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.4.0")]
public partial class ChildEntityContentConfiguration : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<ChildEntityContent>
{
public ChildEntityContentConfiguration()
: this("dbo")
{
}
public ChildEntityContentConfiguration(string schema)
{
ToTable("ChildEntityContent", schema);
HasKey(x => new { x.EntityId, x.ChildEntityId, x.ContentKey });
Property(x => x.EntityId).HasColumnName(@"EntityId").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Property(x => x.ChildEntityId).HasColumnName(@"ChildEntityId").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Property(x => x.ContentKey).HasColumnName(@"ContentKey").HasColumnType("nvarchar").IsRequired().HasMaxLength(100).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Property(x => x.ContentValue).HasColumnName(@"ContentValue").HasColumnType("nvarchar(max)").IsOptional();
// Foreign keys
HasRequired(a => a.Entity).WithMany(b => b.ChildEntityContents).HasForeignKey(c => c.EntityId).WillCascadeOnDelete(false); // FK_ChildEntityContent_Entity
HasRequired(a => a.ChildEntity).WithMany(b => b.ChildEntityContents).HasForeignKey(c => c.ChildEntityId).WillCascadeOnDelete(false); // FK_ChildEntityContent_ChildEntity
InitializePartial();
}
partial void InitializePartial();
}
}
If this is EF 6 then it should look like:如果这是 EF 6,那么它应该如下所示:
return dc.MyEntities
.Include(entity => entity.RelationalEntities)
.Include(entity => entity.RelationalEntities
.Select(rentity => rentity.ChildEntities))
.AsQueryable();
Your second example would be involving conditional, or filtered includes which are only supported in EF Core, in which case I believe it should be:您的第二个示例将涉及仅在 EF Core 中支持的条件或过滤包含,在这种情况下,我认为应该是:
return dc.MyEntities
.Include(entity => entity.RelationalEntities)
.ThenInclude(rentity => rentity.ChildEntities)
.AsQueryable();
Beyond that it would depend on your specific entity definitions to ensure that your relationships between Entity, RelationalEntity, and ChildEntity are configured as proper 1-to-many or many-to-many relationships and not doing something unconventional resulting in them being too loosely associated resulting in unexpected query results.除此之外,这将取决于您的特定实体定义,以确保您将 Entity、RelationalEntity 和 ChildEntity 之间的关系配置为正确的一对多或多对多关系,并且不会做一些非常规的事情,从而导致它们之间的关联过于松散导致意外的查询结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.