将类别父 ID 自引用 table 结构映射到 EF Core 实体
Map category parent id self referencing table structure to EF Core entity
数据库Table:
我尝试使用这种方法将类别 table 映射到 EF 核心:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>(entity =>
{
entity
.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId);
});
}
实体:
[Table("Category"]
public class Category : EntityBase
{
[DataType(DataType.Text), MaxLength(50)]
public string Name { get; set; }
public int? ParentId { get; set; }
public int? Order { get; set; }
[ForeignKey("ParentId")]
public virtual Category Parent { get; set; }
public virtual ICollection<Category> Children { get; set; }
}
然后在存储库中:
public override IEnumerable<Category> GetAll()
{
IEnumerable<Category> categories = Table.Where(x => x.Parent == null).Include(x => x.Children).ThenInclude(x=> x.Children);
return categories;
}
这有效,但无论您调用 Include() 或 ThenInclude() 多少次,都不会返回 3 个级别之后的任何内容。
我最终自己编写了代码以使用递归函数填充子类别:
public override IEnumerable<Category> GetAll()
{
IEnumerable<Category> categories = Table.Where(x => x.Parent == null).ToList();
categories = Traverse(categories);
return categories;
}
private IEnumerable<Category> Traverse(IEnumerable<Category> categories)
{
foreach(var category in categories)
{
var subCategories = Table.Where(x => x.ParentId == category.Id).ToList();
category.Children = subCategories;
category.Children = Traverse(category.Children).ToList();
}
return categories;
}
有谁知道编写存储过程以获取 table 层次结构并映射到我在示例中提供的类别实体的更好方法?
EF(和一般的 LINQ)由于缺少递归 expression/CTE 支持而在加载树状数据时出现问题。
但如果您想加载 整个 树(而不是过滤的树分支),有一个简单的基于 Include
的解决方案。您只需要一个 Include
,然后 EF 导航 属性 修复程序将为您完成这项工作。当您只需要获取示例中的根节点时,诀窍是在通过切换到 LINQ to Objects 上下文(使用 AsEnumerable()
作为查询具体化(并且导航属性被修复)之后应用过滤器通常)。
因此,以下应该通过单个 SQL 查询产生所需的结果:
public override IEnumerable<Category> GetAll()
{
return Table
.AsEnumerable()
.Where(x => x.ParentId == null)
.ToList();
}
数据库Table:
我尝试使用这种方法将类别 table 映射到 EF 核心:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>(entity =>
{
entity
.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId);
});
}
实体:
[Table("Category"]
public class Category : EntityBase
{
[DataType(DataType.Text), MaxLength(50)]
public string Name { get; set; }
public int? ParentId { get; set; }
public int? Order { get; set; }
[ForeignKey("ParentId")]
public virtual Category Parent { get; set; }
public virtual ICollection<Category> Children { get; set; }
}
然后在存储库中:
public override IEnumerable<Category> GetAll()
{
IEnumerable<Category> categories = Table.Where(x => x.Parent == null).Include(x => x.Children).ThenInclude(x=> x.Children);
return categories;
}
这有效,但无论您调用 Include() 或 ThenInclude() 多少次,都不会返回 3 个级别之后的任何内容。
我最终自己编写了代码以使用递归函数填充子类别:
public override IEnumerable<Category> GetAll()
{
IEnumerable<Category> categories = Table.Where(x => x.Parent == null).ToList();
categories = Traverse(categories);
return categories;
}
private IEnumerable<Category> Traverse(IEnumerable<Category> categories)
{
foreach(var category in categories)
{
var subCategories = Table.Where(x => x.ParentId == category.Id).ToList();
category.Children = subCategories;
category.Children = Traverse(category.Children).ToList();
}
return categories;
}
有谁知道编写存储过程以获取 table 层次结构并映射到我在示例中提供的类别实体的更好方法?
EF(和一般的 LINQ)由于缺少递归 expression/CTE 支持而在加载树状数据时出现问题。
但如果您想加载 整个 树(而不是过滤的树分支),有一个简单的基于 Include
的解决方案。您只需要一个 Include
,然后 EF 导航 属性 修复程序将为您完成这项工作。当您只需要获取示例中的根节点时,诀窍是在通过切换到 LINQ to Objects 上下文(使用 AsEnumerable()
作为查询具体化(并且导航属性被修复)之后应用过滤器通常)。
因此,以下应该通过单个 SQL 查询产生所需的结果:
public override IEnumerable<Category> GetAll()
{
return Table
.AsEnumerable()
.Where(x => x.ParentId == null)
.ToList();
}