Я думаю, что один из способов добиться того, что вы пытаетесь сделать, это сделать следующее:
var query= PagesContext.Versions.Where(ve=>ve.ContentStatusID == 2)
.SelectMany(ve=>ve.View.Roles
.Where(r=>r.IsAdminRole == false)
.Select(r=> new RestrictedPage
{
ViewID = ve.ViewID,
Title = ve.Title,
RoleID = r.ID,
Role = r.Role1,
VersionID = ve.VersionID
})).ToList();
В вашем случае таблица соединений не отображается напрямую, это скрыть, так что одно решение для получения данных связано вам нужно использовать метод расширения SelectMany
. Сначала примените условие к одному из концов запроса, в моем примере это было Versions
, а затем примените SelectMany
, которое будет генерировать внутреннее соединение между обеими таблицами и сгладить результат в одной коллекции.
Я думаю, что проблема в том, что версия и View
на самом деле не связаны напрямую с вашей БД, поэтому вы собираетесь сделать явное внутреннее соединение:
var query= PagesContext.Versions.Where(ve=>ve.ContentStatusID == 2)
.Join( PagesContext.Views, ve=>ve.ViewId, v=>v.ID,(ve,v)=>v)
.SelectMany(v=>v.Roles
.Where(r=>r.IsAdminRole == false)
.Select(r=> new RestrictedPage
{
ViewID = ve.ViewID,
Title = ve.Title,
RoleID = r.ID,
Role = r.Role1,
VersionID = ve.VersionID
})).ToList();
Здесь тоже есть код. :)
sub break_recursion(;$) {
my $allowed = @_ ? shift : 1;
my @caller = caller(1);
my $call = $caller[3];
my $count = 1;
for(my $ix = 2; @caller = caller($ix); $ix++) {
croak "found $count levels of recursion into $call"
if $caller[3] eq $call && ++$count > $allowed;
}
}
sub check_recursion(;$) {
my $allowed = @_ ? shift : 1;
my @caller = caller(1);
my $call = $caller[3];
my $count = 1;
for(my $ix = 2; @caller = caller($ix); $ix++) {
return 1
if $caller[3] eq $call && ++$count > $allowed;
}
return 0;
}
Они называются как:
break_recursion(); # to die on any recursion
break_recursion(5); # to allow up to 5 levels of recursion
my $recursing = check_recursion(); # to check for any recursion
my $recursing = check_recursion(10); # to check to see if we have more than 10 levels of recursion.
Могу CPAN это, я думаю. Если у кого-то есть мысли по этому поводу, пожалуйста, поделитесь.
The fact that these are in separate packages has nothing at all to do with the fact that this runs infinitely, consuming all available resources. You're calling two methods from within one another. This isn't circular reference, it's recursion, which is not the same thing. In particular, weaken
won't help you at all. You'd get exactly the same effect from:
sub a {
b();
}
sub b {
a();
}
a();
The best way to avoid this is don't do that. More usefully, if you have to write recursive functions try not to use multiple functions in the recursion chain, but simply the one, so you have an easier time mentally keeping track of where your calls should terminate.
As to how to detect whether something like this is happening, you would have to do something simple like increment a variable with your recursion depth and terminate (or return) if your depth exceeds a certain value. But you really shouldn't have to rely on that, it's similar to writing a while
loop and using an increment there to make sure your function doesn't run out of control. Just don't recurse over a set unless you know how and when it terminates.
Another relevant question would be what are you trying to accomplish in the first place?
Классический разрыв двойной рекурсии - использование переменной состояния, чтобы определить, находитесь ли вы уже внутри функции:
{
my $in_a;
sub a {
return if $in_a; #do nothing if b(), or someone b() calls, calls a()
$in_a = 1;
b();
$in_a = 0;
}
}
Вы можете делать все, что хотите, если $ in_a
истинно, но умереть
, возвращение или возвращение - обычное явление. Если вы используете Perl 5.10 или новее, вы можете использовать функцию состояния
вместо того, чтобы вкладывать функцию в ее собственную область видимости:
sub a {
state $in_a;
return if $in_a; #do nothing if b(), or someone b() calls, calls a()
$in_a = 1;
b();
$in_a = 0;
}
Я предлагаю создать подпрограмму с именем что-то вроде break_constructor_recursion (), которая использует caller () для проверки стека вызовов следующим образом:
Узнайте, какой метод в каком пакете только что вызвал меня.
Просмотрите остальную часть стека вызовов, чтобы увидеть, находится ли этот же метод в этом же пакете где-то еще выше.
Затем вы добавляете вызов break_constructor_recursion () в ваши конструкторы. Если конструктор вызывается изнутри, он взрывается.
Теперь это может привести к ложным срабатываниям; конструктор не может быть законно вызван внутри себя. Если у вас есть проблемы с этим, я бы сказал, просто найдите N дополнительных вхождений конструктора, прежде чем он обнаружит ошибку. Если есть 20 вызовов к системе :: два ::
использовать предупреждения;
без предупреждений:
#!/usr/bin/perl
use strict;
sub foo {
foo();
}
foo();
-
$ perl script.pl ^C # after death
с предупреждениями:
#!/usr/bin/perl
use strict;
use warnings;
sub foo {
foo();
}
foo();
-
$ perl script.pl Deep recursion on subroutine "main::foo" at script.pl line 7. ^C # after death
Всегда всегда используйте предупреждения.
использовать предупреждения FATAL => qw (рекурсия);
#!/usr/bin/perl
use strict;
use warnings FATAL => qw( recursion );
sub foo {
foo();
}
foo();
-
$ perl script.pl Deep recursion on subroutine "main::foo" at script.pl line 7. $