[英]How can I detect reference loops in an EF-generated many-to-many self-reference relationship?
If, for example, I have the following object:例如,如果我有以下 object:
public class Foo
{
public long Id { get; set; }
public IEnumerable<Foo> FooParents { get; set; }
public IEnumerable<Foo> FooChildren { get; set; }
}
How can I effectively detect a circular dependency for a Foo
exemplar (not every circular dependency in DB) from a method within this exemplar?如何从该示例中的方法有效地检测Foo
示例的循环依赖项(不是 DB 中的每个循环依赖项)? I know, what to do in case of one-to-many, but in case of many-to-many, I am a little bit confused.我知道,在一对多的情况下该怎么办,但在多对多的情况下,我有点困惑。 :( :(
Thank you!谢谢!
Here is an implementation with some tests .这是一个带有一些测试的实现。
The interesting bit is here,有趣的一点就在这里,
public static bool IsCircularFoo(Foo foo)
{
var soFar = new HashSet<long>();
soFar.Add(foo.Id);
if (foo.FooParents.Any(foo => IsCircularFooUp(foo, soFar)))
{
return true;
}
return foo.FooChildren.Any(foo => IsCircularFooDown(foo, soFar));
}
private static bool IsCircularFooUp(Foo foo, HashSet<long> soFar)
{
if(soFar.Contains(foo.Id))
{
return true;
}
soFar.Add(foo.Id);
return foo.FooParents.Any(foo => IsCircularFooUp(foo, soFar));
}
private static bool IsCircularFooDown(Foo foo, HashSet<long> soFar)
{
if(soFar.Contains(foo.Id))
{
return true;
}
soFar.Add(foo.Id);
return foo.FooChildren.Any(foo => IsCircularFooDown(foo, soFar));
}
The full working example is here.完整的工作示例在这里。
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var soloFoo = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
Console.WriteLine($"soloFoo isCircular:{IsCircularFoo(soloFoo)}");
var selfParent = new Foo
{
Id = 1,
FooChildren = Enumerable.Empty<Foo>(),
};
selfParent.FooParents = new[] { selfParent };
Console.WriteLine($"selfParent isCircular:{IsCircularFoo(selfParent)}");
var selfChild = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
};
selfChild.FooChildren = new[] { selfChild };
Console.WriteLine($"selfChild isCircular:{IsCircularFoo(selfChild)}");
var parentFoo = new Foo
{
Id = 1,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
var childFoo = new Foo
{
Id = 2,
FooParents = Enumerable.Empty<Foo>(),
FooChildren = Enumerable.Empty<Foo>(),
};
var middleFoo = new Foo
{
Id = 3,
FooParents = new[] { parentFoo },
FooChildren = new[] { childFoo },
};
Console.WriteLine($"middleFoo isCircular:{IsCircularFoo(middleFoo)}");
var ringFooA = new Foo
{
Id = 1,
};
var ringFooB = new Foo
{
Id = 2,
FooParents = new[] { ringFooA },
};
var ringFooC = new Foo
{
Id = 3,
FooParents = new[] { ringFooB },
FooChildren = new[] { ringFooA },
};
ringFooA.FooParents = new[] { ringFooC };
ringFooA.FooChildren = new[] { ringFooB };
ringFooB.FooChildren = new[] { ringFooC };
Console.WriteLine($"ringFooA isCircular:{IsCircularFoo(ringFooA)}");
Console.WriteLine($"ringFooB isCircular:{IsCircularFoo(ringFooB)}");
Console.WriteLine($"ringFooC isCircular:{IsCircularFoo(ringFooC)}");
}
public static bool IsCircularFoo(Foo foo)
{
var soFar = new HashSet<long>();
soFar.Add(foo.Id);
if (foo.FooParents.Any(foo => IsCircularFooUp(foo, soFar)))
{
return true;
}
return foo.FooChildren.Any(foo => IsCircularFooDown(foo, soFar));
}
private static bool IsCircularFooUp(Foo foo, HashSet<long> soFar)
{
if(soFar.Contains(foo.Id))
{
return true;
}
soFar.Add(foo.Id);
return foo.FooParents.Any(foo => IsCircularFooUp(foo, soFar));
}
private static bool IsCircularFooDown(Foo foo, HashSet<long> soFar)
{
if(soFar.Contains(foo.Id))
{
return true;
}
soFar.Add(foo.Id);
return foo.FooChildren.Any(foo => IsCircularFooDown(foo, soFar));
}
}
public class Foo
{
public long Id { get; set; }
public IEnumerable<Foo> FooParents { get; set; }
public IEnumerable<Foo> FooChildren { get; set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.