LINQ join с вложенным выводом foreach razor, выписывающим строки заголовка из groupby

#c# #linq #join #foreach #razor

#c# #linq #Присоединиться #foreach #razor

Вопрос:

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

Товары:

 public class Item
{
    public int ID { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
    public int Order { get; set; }
    public bool Active { get; set; }
    public Category Category { get; set; }
}
  

Категории:

 public class Category
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
    public int Order { get; set; }
    public Menu Menu { get; set; }
}
  

Меню:

 public class Menu
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
    public int Order { get; set; }
}
  

В контроллере у меня есть инструкция linq:

     var model = from i in _db.Items
                join c in _db.Categories on i.Category.ID equals c.ID
                join m in _db.Menus on c.Menu.ID equals m.ID
                where m.Name == menuName
                select i;
  

Я почти уверен, что это не сработает с select i, но у меня закончились идеи, и это текущее состояние.

В представлении, которое я имею:

 @model IEnumerable<MyStore.Models.Item>
  

И я перепробовал все, что мог придумать, чтобы заставить группировку работать, и ничего не получилось. Я даже попытался просто установить переменную в currentCategoryID и проверить, изменилась ли она, а затем записать название категории, но при попадании в @item выдает ошибку.Категория.Имя, указывающее, что ссылка на объект не установлена на экземпляр объекта.

Я полностью потерян. 🙁

ОБНОВЛЕНИЕ Хорошо, мы получили эту часть работы, теперь есть ли способ сделать этот цикл более элегантным? Мне не нравится, когда переменная temp проверяет, является ли это новой категорией.

 int currentCategory = 0;
    foreach (var item in Model)
    {

        if (!item.Category.ID.Equals(currentCategory))
        {
            <h3>@item.Category.Name</h3>
           currentCategory = item.Category.ID;
        }

        <div>
                @Html.DisplayFor(modelItem => item.Name)

            </div>
        <div>

        </div>
    }
  

Ответ №1:

В целом ваш запрос выглядит хорошо и должен выдавать ожидаемые результаты — при условии, что у вас нет свойств null для Menu или Category .

Может ли быть так, что некоторые из ваших категорий содержат null в качестве Menu свойства? В этом случае ваше объединение вызовет исключение NullReferenceException, поскольку вы пытаетесь получить доступ напрямую c.Menu.ID — обходным решением было бы следующее:

 var model = from i in Items
            join c in Categories on i.Category.ID equals c.ID
            where c.Menu !=null
            join m in Menus on c.Menu.ID equals m.ID
            where m.Name == menuName
            select i;
  

Та же проблема с Category свойством Item — если это возможно, null вам нужно исключить эти элементы, поскольку вы используете category.ID свойство:

 var model = from i in Items
            where i.Category != null
            join c in Categories on i.Category.ID equals c.ID
            where c.Menu !=null
            join m in Menus on c.Menu.ID equals m.ID
            where m.Name == menuName
            select i;
  

Редактировать в ответ на комментарий:

Поскольку ни одно свойство не равно null, мы можем снова исключить эту часть из запроса, но вам также необходимо указать, какие связанные объекты вы хотите материализовать при извлечении объектов из контекста. В вашем случае вам также необходимо соответствующее Category свойство, которое вы можете указать с помощью Include() :

 var model = from i in Items.Include("Category")
            join c in Categories on i.Category.ID equals c.ID
            where c.Menu !=null
            join m in Menus on c.Menu.ID equals m.ID
            where m.Name == menuName
            select i;
  

Комментарии:

1. Нет. Ни один из них не равен нулю, я попытался добавить ваше предложение и все еще безрезультатно. По какой-то причине, даже несмотря на то, что intelisense автоматически заполняет @items. Категория. Имя на странице просмотра вызывает истерику, когда я пытаюсь его запустить. @item.Name , item.price и т.д. Работают просто отлично.

2. @Twisted: Ах, теперь мы добираемся до сути: это Linq для сущностей или Linq для SQL? Вам нужно указать, какие связанные объекты вы хотите материализовать.

3. это относится к базе данных. Я вроде как новичок во всем этом, поэтому немного запутался в терминологии. У меня также есть модель DB, и я позволяю entity framework создавать db после того, как я создал классы. Я добавлю, что я удалил все соединения, потому что я не знаю, что они должны быть там, чтобы выполнить то, что я хочу (мой мозг перегрелся, я был на этом весь день), и это все еще дает те же результаты. Я могу получить доступ @item.Name , но не @item.category.name даже если intelisense это видит.

4. Во-первых, ты мой герой. Мой мозг может расслабиться. Однако у меня есть вторая часть вопроса. Я добавил это в обновлении. Мне не нравится метод группировки, который я разработал, но он работает. Есть ли более элегантный способ сделать это?