我想使用EF Core的功能自动将自引用映射到子列表,即使在加载平面结构时也是如此。此外,我希望能够减少读取和传输的列数
我的自参考数据结构:
public class Item
{
public int property1 { get; set; }
/*
Realy long list of columns
*/
public int property30 { get; set; }
public Guid? ParentOid { get; set; }
public virtual Item Parent { get; set; }
public virtual ICollection<OtherObject> OtherObjects { get; set; }
public virtual ICollection<Item> Children { get; set; }
}
我想实现整个层次树的加载,这可以通过使用以下查询轻松完成:
(DbContext context) => context.Items.AsQueryable()
然后用进行过滤
var rootNodes = items.Where(f => f.ParentOid == null)
通过这种方式,Ef Core已经在树中的所有Children上填充了Children集合,这就是我需要的行为
这个查询传输了相当大的数据量,因为property1-property30都已加载,而我只需要其中的一个子集。
通过将LINQ select语句与匿名类型一起使用,我失去了自动构建树的行为,我将不得不自己完成这项工作。
我当前的解决方案
通过设置另一个没有属性的模型Item.cs,我不需要它们出现在SQL查询的select语句中。
这个解决方案的问题是,我需要将Item.cs的名称更改为例如ItemWithLessProperties.cs,并将其添加到当前上下文中。这将在OtherObject.cs中创建冲突,因为它持有Item而不是ItemWithLessProperties的引用。所以,我必须复制这个,并将其添加到上下文中。
通过使用完全不同的上下文来实现这一目的,我还将拥有Models Item(这不是一个大问题(和OtherObject(这是一个问题,因为它们有多个(的副本。
听起来你需要一个ItemDTO
。你可以创建一个类似的对象
public class ItemDTO
{
/*
Properties you need
*/
public int property1 { get; set; }
public int property5 { get; set; }
public int property17 { get; set; }
public int property30 { get; set; }
public virtual ICollection<OtherObject> OtherObjects { get; set; }
public virtual ICollection<Item> Children { get; set; }
}
如果您想将每个嵌套实体也包含在可查询对象中,还可以为其添加DTO。
然后你可以简单地var dtoItems = context.Items.Where(condition).Select(i=>new ItemDTO {/* initialize props */});
注意:如果您没有使用DTO,并且您提取的数据将严格只读,并且您不会尝试更新数据库中当前提取的条目,那么也可以使用.AsNoTracking()
来避免EF Core的更改跟踪开销。