使用Ef-Core在分层数据中选择特定列



我想使用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的更改跟踪开销。

最新更新