Ing*_*mar 7 entity-framework ef-code-first entity-framework-6
我试图用EF 6.1.2 Code First实现一个简单的自引用关系.
public class Branch
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Branch Parent { get; set; }
public ICollection<Branch> Children { get; set; } // direct successors
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我只有一个根分支.除了这个单根分支外,每个分支只有一个父分支(根分支的parentId为NULL).除此之外,每个分支都可以有[0..n]个子分支.
我有两个问题:
modelBuilder.Entity<Branch>().HasOptional<Branch>(b => b.Parent).WithMany(b => b.Children).HasForeignKey(b => b.ParentId);但我不确定我是否需要这个..
public IEnumerable<Branch> GetBranches(Branch anyBranch)
{
return anyBranch.Flatten(b => b.Children);
}
Run Code Online (Sandbox Code Playgroud)
和
public static IEnumerable<T> Flatten<T>(this T node, Func<T, IEnumerable<T>> selector)
{
return selector(node).SelectMany(x => Flatten(x, selector))
.Concat(new[] { node });
}
Run Code Online (Sandbox Code Playgroud)
第二个片段不是来自我.我发现它在StackOverflow上的其他地方.说实话,我几乎不明白它应该如何工作.
当我运行我的应用程序并调用GetBranches()(我尝试使用几个不同的分支)时,我在Flatten()方法中收到一个异常.错误消息显示:"值不能为null.参数名称:source".不幸的是,这并没有让我知道这里出了什么问题.
我希望有人可以帮助我吗?非常感谢!
Ger*_*old 10
该异常是由一个Select或SelectMany一个null集合引起的,在您的情况下是一个集合的结果
b => b.Children
Run Code Online (Sandbox Code Playgroud)
对于层次结构中的每个分支,Children集合在到达零件时被访问
selector(node)
Run Code Online (Sandbox Code Playgroud)
的selector是λ表达式b => b.Children,其是相同的方法
IEnumerable<Branch> anonymousMethod(Branch b)
{
return b.Children;
}
Run Code Online (Sandbox Code Playgroud)
那么实际发生的是b.Children.SelectMany(...),或者null.SelectMany(...),这会引发您看到的异常.
但为什么这些Children收藏品无效?
这是因为延迟加载不会发生.要启用延迟加载,集合必须是virtual:
public virtual ICollection<Branch> Children { get; set; }
Run Code Online (Sandbox Code Playgroud)
当EF Branch从数据库中获取对象时,它会创建一个proxy对象,一个派生自的对象Branch,它通过能够延迟加载的代码覆盖虚拟属性.现在,当b.Children解决时,EF将执行填充集合的查询.如果没有子节点,则集合将为空,不为空.
所以在该Flatten方法中发生的事情是首先获取分支的子节点(selector(node)),随后在每个子节点上(SelectMany)Flatten再次调用该方法(现在仅作为方法Flatten(x, selector),而不是扩展方法).
在该Flatten方法中,每个节点都被添加到其子节点的集合中(.Concat(new[] { node })最终,返回层次结构中的所有节点(因为Flatten返回进入它的节点).
我想将父节点放在集合的顶部,所以我将Flatten方法更改为
public static IEnumerable<T> Flatten<T>(this T node, Func<T,IEnumerable<T>> selector)
{
return new[] { node }
.Concat(selector(node).SelectMany(x => Flatten(x, selector)));
}
Run Code Online (Sandbox Code Playgroud)通过延迟加载获取层次结构是非常低效的.实际上,LINQ不是最适合查询层次结构的工具.有效地执行此操作将需要数据库中使用CTE(公用表表达式)的视图.但那是一个不同的故事......
| 归档时间: |
|
| 查看次数: |
4217 次 |
| 最近记录: |