В EF Core, как решить круговую ссылку цепочки Include ThenInclude? - PullRequest
0 голосов
/ 07 января 2020

Рассмотрим следующий сценарий. У меня есть 3 класса, представляющих отношения многие-ко-многим (N-to-N) между учеником и предметом:

public class Student
{
    public long Id { get; set; }
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
    public long RegistrationNumber { get; set; }

    public virtual ICollection<Grade> Grades { get; set; }
}
public class Grade
{
    public long Id { get; set; }
    public int Value { get; set; }

    public virtual Student Student { get; set; }
    public virtual Subject Subject { get; set; } 
}
public class Subject
{
    public long Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Grade> Grades { get; set; }
}

Я хочу получить список всех студентов с их оценками по каждому предмету. Для этого я использую:

// context being DbContext
var res = context.Student.Include(s => s.Grades).ThenInclude(g => g.Subject);

Поскольку свойства загружаются отложенным образом, я ожидал, что каждый объект будет содержать только свое свойство «Имя». Однако при проверке я обнаружил, что список «Оценки» также установлен со списком всех оценок, присвоенных предмету. Это, конечно, вызывает объектный цикл. Я хочу избежать этой циклической ссылки, то есть получить список, где единственным установленным свойством каждого субъекта является «Имя». Как я могу это сделать?

Ответы [ 3 ]

0 голосов
/ 07 января 2020

Если вы используете asp. net core 3.0 MVC / Web API, просто следуйте приведенным ниже шагам, чтобы преодолеть циклическую ссылку, используя NewtonsoftJson.

1.Установите Microsoft.AspNetCore.Mvc.NewtonsoftJson пакет (версия зависит от ваш проект)

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0

2.Добавьте приведенный ниже код при запуске

services.AddControllersWithViews().AddNewtonsoftJson(x =>
        {
            x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });
0 голосов
/ 16 января 2020

Следуя совету Джавада, я использовал операторы LINQ Select.

Сначала я написал несколько DTO:

public class StudentDTO
{
    public string Name { get; set; }

    public DateTime Birthday { get; set; }

    public long RegistrationNumber { get; set; }

    public IEnumerable<GradeDTO> Grades { get; set; }
}
public class GradeDTO
{
    public int Value { get; set; }

    public virtual StudentDTO Student { get; set; }
    public virtual SubjectDTO Subject { get; set; }

}
public class SubjectDTO
{
    public string Name { get; set; }

    public virtual IEnumerable<GradeDTO> Grades { get; set; }
}

А затем:

var res = from student in context.Student
          select new StudentDTO
          {
              Name = student.Name,
              Birthday = student.Birthday,
              RegistrationNumber = student.RegistrationNumber,
              Grades = from grade in student.Grades
                       select new GradeDTO
                       {
                           Value = grade.Value,
                           Subject = new SubjectDTO
                           {
                               Name = grade.Subject.Name
                           }
                       }
          };
0 голосов
/ 07 января 2020

Вы всегда можете вручную выбрать только имя, например

   context.Student.Select(x => x.Name);

Но это не работает со свойствами навигации и автоматически создаваемыми объединениями между таблицами. Там «все или ничего».

Или вы должны выполнить соединение полностью вручную, без свойств навигации.

Но ваша структура не так уж сложна и не уязвима для округлостей. Просто начните с Grade, с якорным элементом посередине.

  context.Grade.Include(x => Subject).Include(x =>Student)

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

Может быть, вы добавите

   .GroupBy(x => x.Student)

, чтобы приблизиться к вашему списку студентов.

Вы не можете пропустить «загрузку» коллекции, потому что это оценки, которые загружается первым. Итак, сначала есть элементы коллекции, а затем субъект субъекта. Нет смысла не помещать данные в сборник.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...