Как Платформа Объекта работает с рекурсивными иерархиями? Включайте (), кажется, не работает с ним

Просто необходимо выбрать свойство, которое Вы хотите от объектов. FullName в этом случае.

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName}

Править: Объяснение Mark, который спрашивает, "Что делает foreach? Что это перечисляет?"

Объяснение Sung Meister очень хорошо, но я добавлю пошаговую демонстрацию здесь, потому что это могло быть полезно.

Ключевое понятие является конвейером. Изобразите серию шаров пинг-понга, катящихся по узкой трубе один за другим. Это объекты в конвейере. Каждый этап конвейера - сегментов кода, разделенных каналом (|) символы - имеет канал, входящий в него и канал, выходящий из него. Вывод одного этапа подключен к входу следующего этапа. Каждый этап берет объекты, когда они прибывают, делает вещи им, и передает их обратно в выходной конвейер или отсылает новый, заменяющие объекты.

Get-ChildItem $directory -Recurse

Получите-ChildItem обходы посредством создания файловой системы объекты FileSystemInfo, которые представляют каждый файл и каталог, с которым это встречается и помещает их в конвейер.

Select-Object FullName

Избранный объект берет каждый объект FileSystemInfo, когда он прибывает, захватывает свойство FullName от него (который является путем в этом случае), помещает то свойство в совершенно новый пользовательский объект, который он создал и производит тот пользовательский объект в конвейер.

Where-Object {!($_.psiscontainer)}

Это - фильтр. Это берет каждый объект, исследует его, и передает его обратно или отбрасывает его в зависимости от некоторого условия. Ваш код здесь имеет ошибку, между прочим. Пользовательские объекты, которые прибывают сюда, не имеют psiscontainer свойства. Этот этап ничего на самом деле не делает. Код Sung Meister лучше.

foreach {$_.FullName}

Foreach, длинное имя которого является ForEach-объектом, захватывает каждый объект, как он прибывает, и сюда, захватывает свойство FullName, строку, от него. Теперь, вот тонкая часть: Любое значение, которое не используется, то есть, не получено переменной или подавлено в некотором роде, помещается в выходной конвейер. Как эксперимент, попытайтесь заменить тот этап этим:

foreach {'hello'; $_.FullName; 1; 2; 3}

На самом деле испытайте его и исследуйте вывод. В том блоке кода существует четыре значения. Ни один из них не используется. Заметьте, что они все появляются в выводе. Теперь попробуйте это:

foreach {'hello'; $_.FullName; $ x = 1; 2; 3}

Заметьте, что одно из значений получается переменной. Это не появляется в выходном конвейере.

68
задан Shimmy 2 November 2015 в 23:38
поделиться

4 ответа

Вместо использования метода Include вы можете использовать Load .

Затем вы можете выполнить для каждого и перебрать все дочерние элементы, загружая своих детей. Затем проделайте по каждому через их детей и так далее.

Количество уровней вниз будет жестко закодировано в количестве для каждой имеющейся петли.

Вот пример использования Load : http://msdn.microsoft.com/en-us/library/bb896249.aspx

22
ответ дан 24 November 2019 в 14:23
поделиться

Лучше ввести таблицу сопоставления, которая сопоставляет каждую категорию родительской и дочерней, вместо добавления родительского и дочернего свойства к грузу.

В зависимости от того, как часто вам нужна эта информация, ее можно запросить по запросу. С помощью уникальных ограничений в базе данных вы можете избежать бесконечного количества возможных отношений.

3
ответ дан 24 November 2019 в 14:23
поделиться

Это может быть опасно, если вы загрузите все рекурсивные сущности, особенно по категориям, вы можете получить ПУТЬ больше, чем вы рассчитывали:

Category > Item > OrderLine > Item
                  OrderHeader > OrderLine > Item
         > Item > ...

Внезапно вы загрузив большую часть вашей базы данных, вы также можете загрузить строки счетов-фактур, затем клиентов, а затем все их счета-фактуры.

Что вы должны сделать, это примерно следующее:

var qryCategories = from q in ctx.Categories
                    where q.Status == "Open"
                    select q;

foreach (Category cat in qryCategories) {
    if (!cat.Items.IsLoaded)
        cat.Items.Load();
    // This will only load product groups "once" if need be.
    if (!cat.ProductGroupReference.IsLoaded)
        cat.ProductGroupReference.Load();
    foreach (Item item in cat.Items) {
        // product group and items are guaranteed
        // to be loaded if you use them here.
    }
}

Однако лучшим решением является создание вашего запроса для построения анонимный класс с результатами, поэтому вам нужно всего лишь один раз обратиться к хранилищу данных.

var qryCategories = from q in ctx.Categories
                    where q.Status == "Open"
                    select new {
                        Category = q,
                        ProductGroup = q.ProductGroup,
                        Items = q.Items
                    };

Таким образом, вы можете вернуть результат словаря, если требуется.

Помните, ваши контексты должны быть как можно более короткими.

6
ответ дан 24 November 2019 в 14:23
поделиться

If you definitely want the whole hierarchy loaded, then if it was me I'd try writing a stored procedure who's job it is to return all the items in a hierarchy, returning the one you ask for first (and its children subsequently).

And then let the EF's relationship fixup ensure that they are all hooked up.

i.e. something like:

// the GetCategoryAndHierarchyById method is an enum
Category c = ctx.GetCategoryAndHierarchyById(1).ToList().First();

If you've written your stored procedure correctly, materializing all the items in the hierarchy (i.e. ToList()) should make EF relationship fixup kicks in.

And then the item you want (First()) should have all its children loaded and they should have their children loaded etc. All be populated from that one stored procedure call, so no MARS problems either.

Hope this helps

Alex

14
ответ дан 24 November 2019 в 14:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: