gpt4 book ai didi

c# - 使用 Entity Framework 的自引用树的最有效方法

转载 作者:IT王子 更新时间:2023-10-29 04:03:27 25 4
gpt4 key购买 nike

所以我有一个基本上是 SQL 表

ID, ParentID, MenuName, [Lineage, Depth]

最后两列是自动计算的,以帮助搜索,所以我们现在可以忽略它们。

我正在创建一个包含多个类别的下拉菜单系统。

不幸的是,我认为 EF 不能很好地处理深度超过 1 级的自引用表。所以我有几个选择

1) 创建查询,按深度排序,然后在 C# 中创建自定义类,一次填充一个深度。

2) 找到一些方法来预加载 EF 中的数据,我认为对于无限数量的关卡是不可能的,只能是固定数量。

3) 我什至不确定的其他方式。

欢迎任何意见!

最佳答案

我已使用 EF 成功映射分层数据。

Establishment 实体为例。这可以代表公司、大学或更大组织结构中的其他一些单位:

public class Establishment : Entity
{
public string Name { get; set; }
public virtual Establishment Parent { get; set; }
public virtual ICollection<Establishment> Children { get; set; }
...
}

这是父/子属性的映射方式。这样,当您设置 1 个实体的 Parent 时,Parent 实体的 Children 集合会自动更新:

// ParentEstablishment 0..1 <---> * ChildEstablishment
HasOptional(d => d.Parent)
.WithMany(p => p.Children)
.Map(d => d.MapKey("ParentId"))
.WillCascadeOnDelete(false); // do not delete children when parent is deleted

请注意,到目前为止我还没有包含您的 Lineage 或 Depth 属性。没错,EF 不能很好地生成具有上述关系的嵌套分层查询。我最终确定的是添加一个新的动名词实体,以及 2 个新的实体属性:

public class EstablishmentNode : Entity
{
public int AncestorId { get; set; }
public virtual Establishment Ancestor { get; set; }

public int OffspringId { get; set; }
public virtual Establishment Offspring { get; set; }

public int Separation { get; set; }
}

public class Establishment : Entity
{
...
public virtual ICollection<EstablishmentNode> Ancestors { get; set; }
public virtual ICollection<EstablishmentNode> Offspring { get; set; }

}

在写这篇文章时,hazzik posted an answer that is very similar to this approach .不过,我会继续写下去,以提供一个略有不同的替代方案。我喜欢让我的 Ancestor 和 Offspring 动名词类型成为实际的实体类型,因为它帮助我获得 Ancestor 和 Offspring 之间的分离(你称之为深度)。以下是我如何映射这些:

private class EstablishmentNodeOrm : EntityTypeConfiguration<EstablishmentNode>
{
internal EstablishmentNodeOrm()
{
ToTable(typeof(EstablishmentNode).Name);
HasKey(p => new { p.AncestorId, p.OffspringId });
}
}

...最后是 Establishment 实体中的识别关系:

// has many ancestors
HasMany(p => p.Ancestors)
.WithRequired(d => d.Offspring)
.HasForeignKey(d => d.OffspringId)
.WillCascadeOnDelete(false);

// has many offspring
HasMany(p => p.Offspring)
.WithRequired(d => d.Ancestor)
.HasForeignKey(d => d.AncestorId)
.WillCascadeOnDelete(false);

此外,我没有使用存储过程来更新节点映射。相反,我们有一组内部命令,这些命令将根据父子属性派生/计算祖先和后代属性。但是最终,您最终能够进行一些与 hazzik 的回答非常相似的查询:

// load the entity along with all of its offspring
var establishment = dbContext.Establishments
.Include(x => x.Offspring.Select(y => e.Offspring))
.SingleOrDefault(x => x.Id == id);

主要实体和它的祖先/后代之间的桥梁实体的原因再次是因为这个实体让你得到分离。此外,通过将其声明为标识关系,您可以从集合中删除节点,而无需对它们显式调用 DbContext.Delete()。

// load all entities that are more than 3 levels deep
var establishments = dbContext.Establishments
.Where(x => x.Ancestors.Any(y => y.Separation > 3));

关于c# - 使用 Entity Framework 的自引用树的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11565423/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com