Ядро Entity Framework : получение данных из связанных таблиц с включением

#c# #entity-framework-core #asp.net-core-webapi

Вопрос:

Я пытаюсь получить данные из пяти таблиц: Категория — Подкатегория — Вторая категория — тип — нагрев, которые все связаны с основной таблицей (свойство).

Таблицы (категория — подкатегория — Вторая категория) связаны как слои (Категория => Подкатегория =>> Вторая категория)

Я попытался получить данные с помощью:

 public IActionResult getAllProperties()
{
      var properties = db.properties
                         .Include(cat => cat.category)
                         .Include(sub => sub.subCategory)
                         .Include(sec => sec.SecondSubCategory)
                         .Include(e => e.heating)
                         .Include(e => e.type)        
                         .OrderByDescending(x => x.id)
                         .ToList();
      return Ok(properties);
}
 

но возвращенные данные содержали значения для полей типа и типа, но с нулевыми значениями для (CategoryID и subCategoryId и secondSubCategoryId), зная, что эти поля имеют значения

Property.cs

 public class Property
{
    [Key]
    public int id { get; set; }    

    public int typeId { get; set; }
    public type type { get; set; }

    public int heatingId { get; set; }
    public heating heating { get; set; }

    public int? categoryId { get; set; }
    public category category { get; set; }

    public int? subCategoryId { get; set; }
    public subCategory subCategory { get; set; }

    public int? secondSubCategoryId { get; set; }
    public SecondSubCategory SecondSubCategory { get; set; }
}
 

Ответ без включения категории и подкатегории и второй субкатегории :

  {
        "id": 14,        
        "typeId": 1,
        "type": {
            "id": 1,
            "typeName": "Flat"
        },
        "heatingId": 4,
        "heating": {
            "id": 4,
            "heatingName": "Conditioning"
        },
        "categoryId": 1,
        "category": null,
        "subCategoryId": 2,
        "subCategory": null,
        "secondSubCategoryId": 3,
        "secondSubCategory": null
    }
 

Response with including category and subCategory and secondSubCategory :

 {
        "id": 14,        
        "typeId": 1,
        "type": {
            "id": 1,
            "typeName": "Flat"
        },
        "heatingId": 4,
        "heating": {
            "id": 4,
            "heatingName": "Conditioning"
        },
        "categoryId": null,
        "category": null,
        "subCategoryId": null,
        "subCategory": null,
        "secondSubCategoryId": null,
        "secondSubCategory": null
}
 

Категория.cs

 public class category
  {
    public int id { get; set; }

    public string category_Name { get; set; }

    public IList<subCategory> subCategories { get; set; }
    public Property Property { get; set; }

  }
 

Подкатегория.cs:

 public class subCategory
    {
    public int id { get; set; }

    public string subCategoryName { get; set; }



    public int CategoryId { get; set; }
    public category category { get; set; }

    public IList<SecondSubCategory> secondSubCategories { get; set; }
    public Property Property { get; set; }
  }
 

Вторая категория.cs:

 public class SecondSubCategory
  {
    public int id { get; set; }

    public string subCategoryName { get; set; }


    public int subCategoryId { get; set; }
    public subCategory subCategory { get; set; }

    public Property Property { get; set; }
  }
 

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

1. Какова цель .Include(cat=>cat.category) запроса?

2. Можете ли вы показать категорию или подкатегорию класса

3. @atiyar цель состоит в том, чтобы получить данные из категории, относящейся к собственности

4. Но вы уже .Include(s=>s.category) сделали это для этого.

5. @Сергей public class category { public int id { get; set; } public string category_Name { get; set; } public IList<subCategory> subCategories { get; set; } public Property Property { get; set; } }

Ответ №1:

Сначала я использую код для создания базы данных с вашими моделями и тестирования с некоторыми данными. Если я не включу категорию, подкатегорию и вторую субкатегорию, результат будет таким же, как у вас, но когда я их включу, возникнет ожидание:

Исключение JSONException: Обнаружен возможный цикл объектов, который не поддерживается. Это может быть связано либо с циклом, либо с глубиной объекта, превышающей максимально допустимую глубину 32.

Затем я использую NewtonsoftJson для решения проблемы с обработкой ссылок

 services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
     options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
 

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

Ответ №2:

Как я понял из ваших сущностей, вы должны следовать принципам иерархии при проектировании своей базы данных. Это моя рекомендация:

 public class Property
{
    [Key]
    public int id { get; set; }    

    public int typeId { get; set; }
    public type type { get; set; }

    public int heatingId { get; set; }
    public heating heating { get; set; }

    public int? categoryId { get; set; }
    public category category { get; set; }
}

public class category
  {
    public int id { get; set; }
    public string category_Name { get; set; }

    public IList<subCategory> subCategories { get; set; }
    public Property Property { get; set; }

  }

public class subCategory
  {
    public int id { get; set; }
    public string subCategoryName { get; set; }

    public int CategoryId { get; set; }
    public category category { get; set; }

    public IList<SecondSubCategory> secondSubCategories { get; set; }
  }


public class SecondSubCategory
  {
    public int id { get; set; }
    public string secondCategoryName { get; set; }

    public int subCategoryId { get; set; }
    public subCategory subCategory { get; set; }
  }
 

И вот как вы можете получить данные своей иерархии:

 public IActionResult getAllProperties()
{
      var properties = db.properties
                         .Include(cat => cat.category)
                             .ThenInclude(sub => sub.subCategory)
                                .ThenInclude(sec => sec.SecondSubCategory)
                         .Include(e => e.heating)
                         .Include(e => e.type)        
                         .OrderByDescending(x => x.id)
                         .ToList();
      return Ok(properties);
}
 

Ответ №3:

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

 public IActionResult getAllProperties()
{
 var properties = ( from p in  db.properties
 join  c in  db.category on p.categoryId equals c.Id into cj
 from c in cj.DefaultIfEmpty()
 join  sc in  db.subCategory on on p.subCategoryId equals sc.Id into scj
 from sc in scj.DefaultIfEmpty()
 join  ssc in  db.secondSubCategory on on p.secondSubCategoryId equals ssc.Id into sscj
 from ssc in sscj.DefaultIfEmpty()
join  h in  db.heatings on p.heatingId equals h.Id 
join  t in  db.types on p.typeId equals t.Id 
orderby  p.id descending
select new Property {
id= p.id 
 typeId=p.typeId,
 type=t,
 heatingId = p.heatingId,
 heating=h, 
 categoryId = p.categoryId,
category =c,
subCategoryId= p.subCategoryId,
subCategory=sc,
secondSubCategoryId=p.secondSubCategoryId,
SecondSubCategory=ssc 
}).ToList();

 return Ok(properties);
}

 

или немного короче:

 var properties = ( from p in  db.properties
 join  c in  db.category on p.categoryId equals c.Id into cj
 from c in cj.DefaultIfEmpty()
 join  sc in  db.subCategory on on p.subCategoryId equals sc.Id into scj
 from sc in scj.DefaultIfEmpty()
 join  ssc in  db.secondSubCategory on on p.secondSubCategoryId equals ssc.Id into sscj
 from ssc in sscj.DefaultIfEmpty()
orderby  p.id descending
select new Property {
id= p.id 
 typeId=p.typeId,
 type=p.type,
 heatingId = p.heatingId,
 heating=p.heading, 
 categoryId = p.categoryId,
category =c,
subCategoryId= p.subCategoryId,
subCategory=sc,
secondSubCategoryId=p.secondSubCategoryId,
SecondSubCategory=ssc 
}).ToList();
 

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

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

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