Как выбрать и сгруппировать поля с помощью LINQ?

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

 [HttpGet]
    public object Get()
    {
        return new { Items = _context.farmtable
        .Select(x => new {x.Id, x.Item, x.Store, x.Location })
        .ToList(), Count = _context.farmtable.Count() };
    }
Идентификатор Элемент Магазин Расположение 1 Яблоко Дом А Линия-04 2 манго Дом Б Линия-23 1 Яблоко Дом А Линия-15 1 Яблоко Дом Б Линия-08 3 Банан Дом А Линия-02

Это то, что я пробовал, но ничего не отображается.

[HttpGet]
    public object Get()
    {
        return new { Items = _context.farmtable.GroupBy(x => x.Store, x => x.Item )
       .Select(group => new { Store = group.Key, Item = group.Key, Items = group.ToList() })
       .ToList(), Count = _context.farmtable.Count() };         
    }

Ожидаемый результат

Магазин Элемент Считать Дом А Яблоко 2 Дом А Банан 1 Дом Б Яблоко 1 Дом Б манго 1

Какой у Вас вопрос? У вас возникла ошибка или что-то в этом выводе не соответствует вашим ожиданиям? Лучше быть откровенным, чем предполагать, что мы догадаемся правильно!

Richard 01.05.2024 13:55

Вам следует перестать пересматривать то, что делает этот код, потому что он полон проблем и противоречий. Предполагая, что _context — это DbContext, вы имеете дело не с таблицами, а с сущностями приложения. Сеток нет. Это Get возвращает список объектов, НО стирает типы. Все API используют для результатов конкретные типы, а не анонимные типы. Этот метод все равно ничего не отображает, он возвращает JSON. Хуже того, сам запрос EF является частью анонимного типа, поэтому вы даже не можете увидеть, какая часть запроса и куда его поместить GroupBy.

Panagiotis Kanavos 01.05.2024 14:38

Что ты вообще пытаешься вернуть? Ожидаемый результат — это просто уникальные комбинации Store и Item без подсчетов или чего-то еще. Запрос пытается вернуть все отдельные элементы в корзинах магазина. Это ничем не отличается от загрузки всех элементов в память и их последующей группировки. Он не может использовать GROUP BY в SQL.

Panagiotis Kanavos 01.05.2024 14:42

Как насчет farmtable.GroupBy(item => (item.Store, item.Item)).Select(group => (group.Key, group.Count()). Это должно работать с IEnumerable. Если вы имеете дело с базой данных и это IQueryable, то это зависит от вашего поставщика базы данных.

Oliver 01.05.2024 16:12

_context.Farmtable .Select(x => new { Store = x.Store, Item = x.Item }) .GroupBy(g => new { g.Store, g.Item }) .Select(s => new { s .Key.Store, s.Key.Item, count = s.Count()})

Power Mouse 03.05.2024 18:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

[HttpGet]
public object Get()
{
    return _context.Farmtable.AsNoTracking()
                .Select(x => new { Store = x.Store, Item = x.Item })
                .GroupBy(g => new { g.Store, g.Item })
                .Select(s => new { Store = s.Key.Store, Item = s.Key.Item, count = s.Count() });
}
Ответ принят как подходящий

Сначала повышение эффективности

По соображениям эффективности при объединении операторов LINQ следует сохранять промежуточные результаты IEnumerable<...> (или IQueryable<...>) как можно дольше. Поэтому не используйте ToList или ToArray, если вы не собираетесь использовать результаты.

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

Например, если звонящий на ваш Get хочет только узнать, есть ли какой-нибудь предмет, который можно получить:

public bool AreFarmsAvailabe()
{
    return this.Get().Any();
}

Если метод Get использует ToList, то в список помещаются тысячи ферм, и единственное, что при этом делается, — это проверка, есть ли что-нибудь в списке. Так что вы могли бы остановиться, как только у вас будет одна ферма.

Поэтому рассмотрите возможность изменения метода Get

class FarmStoreLocation             // TODO: invent a proper name
{
    public int Id {get; set;}
    public string Item {get; set;}        // might be an enum, or a class
    public string Store {get; set;}
    public string Location {get; set;}
}

И ваш метод Get:

IEnumerable<FarmStoreLocation> GetFarmStoreLocations()
{
    IEnumerable<FarmStoreLocation> fetchedFarmStoreLocations = _context.FarmTable
    .Select(farm => new FarmStoreLocation
    {
        Id = farm.Id,
        Item = farm.Item,
        Store = farm.Store,
        Location = farm.Location,
    });

    return fetchedFarmStoreLocations;
}

Я не знаю, возвращает ли ваш _context.FarmTable IEnumerable<...> или IQueryable<...>, если последнее, то пусть процедура возвращает IQueryable.

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

Вернемся к вашему вопросу

Требование: Учитывая входную последовательность FarmStoreLocations, преобразуйте ее в последовательность комбинаций [Магазин, Товар] и подсчитайте, сколько этих комбинаций находится во входной последовательности.

Итак, вы хотите посчитать, сколько раз вы видите комбинацию [Дом А, Яблоко] и сколько раз вы видите комбинацию [Дом А, Банан] и т. д.

Как вы уже поняли, для этого вам понадобится одна из перегрузок Enumerable.GroupBy. Вы хотите создать группы FarmStoreLocations с одинаковым значением для [Store, Item]. После этого вам нужно подсчитать количество FarmStoreLocations в каждой группе. Для этого я использую перегрузку Enumerable.GroupBy, имеющую оба параметра KeySelector и ResultSelector:

IEnumerable<FarmStoreLocation> farmStoreLocations = GetFarmStoreLocations();

var countedStoreItems = farmStoreLocations.GroupBy (

// parameter keySelector: make groups of farmStoreLocations that have the same
// value for [Store, Item]
farmStoreLocation => new
{
    Store = farmStoreLocation.Store,
    Item = farmStoreLocation.Item,
},

// parameter resultSelector: from every found combination of [Store, Item]
// and all farmStoreLocations that have these values for Store and Item
// make one new:
(storeItemCombination, farmStoreLocationsWithThisStoreItemCombination) => new
{
    Store = storeItemCombination.Store,
    Item = storeItemCombination.Item,

    Count = farmStoreLocationsWithThisStoreItemCombination.Count(),
});

Другими словами: из входной последовательности FarmStoreLocations создайте группы FarmStoreLocations, которые имеют одинаковое значение свойств Store и Item. Ключом группы является объект-комбинация [Магазин, Товар].

Результатом является последовательность групп, где каждая группа будет иметь ключ, который представляет собой [Store, Item], и все FarmStoreLocations, которые имеют эти значения для Store и Item.

Из каждой группы возьмите ключ (= одну комбинацию storeItemCombination) и всех членов группы (= все фермыStoreLocations с этой комбинацией storeItemCombination) и создайте для каждой группы ровно один объект.

Этот один объект содержит значение Store, которое есть у всех FarmStoreLocations группы, и значение Item, которое есть у всех FarmStoreLocations группы. Наконец, этот объект содержит количество FarmStoreLocations в группе.

Другие вопросы по теме