Entity Framework Core отключает рекурсивный поиск информации в функции .Include () - PullRequest
0 голосов
/ 12 февраля 2020

В базе есть таблицы Machines, Wheels, Характеристики и Pilot. 1 запись автомобиля включает в себя 1 запись о пилоте, 4 записи колеса и несколько характеристик. В моем классе Models это выглядит примерно так:

public class Machines
{
    public int Id { get; set; }
    public string Description { get; set; }
    public string Color { get; set; }
    public int Weight { get; set; }
    public int Param { get; set; }

    public List<Characteristics> characteristics { get; set; }
    public List<Wheels> wheels { get; set; }
    public Pilot pilot { get; set; }
}
public class Characteristics
{
    public int Id { get; set; }
    public string Parameter { get; set; }
    public string Value { get; set; }
    public string Description { get; set; }

    public int MachineId { get; set; }
    [ForeignKey("MachineId")]
    public Machines machine{ get; set; }

}
public class Wheels
{
    public int Id { get; set; }
    public int Radius { get; set; }
    public int Weight { get; set; }
    public int MachineId { get; set; }

    [ForeignKey("MachineId")]
    public Machines machine{ get; set; }
}
public class Pilot
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; } 
    public int MachineId { get; set; }

    [ForeignKey("MachineId")]
    public Machines machine{ get; set; }
}

Когда я пытаюсь загрузить полную информацию о машине, подобной этой:

 var car  = context.Machines.Where(x => x.Id == 2)
                        .Include(m=> m.Wheels)
                        .Include(m=>m.Charateristics)
                        .Include(m=>m.Pilot)
                        .FirstOrDefault();

В ответ я получаю автомобиль, который содержит пилота, массив всех характеристик и массив колес. Но в то же время массив колес снова содержит информацию об автомобиле, в которую входит информация о колесах (но уже во второй раз без автомобиля).

Это выглядит примерно так:

{
"id": 2,
"Description": "",
"Color": "red",
"Weight": 2000,
"Pilot": {
    "id": 1,
    "Name": "John",
    "Description": ""
}, 
"Wheels": [
    {
        "id": 7,
        "Radius": 14,
        "Weight": 5,
        "MachineId": 2, 
        "machine": {
            "id": 2,
            "Description": "",
            "Color": "red",
            "Weight": 2000,
            "Pilot": {
                "id": 1,
                "Name": "John",
                "Description": ""
            }, 
            "Wheels": [
                {
                    "id": 7,
                    "Radius": 14,
                    "Weight": 5,
                    "MachineId": 2
                },
...

Как получить информацию без рекурсивных данных?

Кроме того, запрос занимает очень много времени (намного дольше, чем 4 отдельные запросы). На веб-сайте Microsoft говорится, что вы можете отключить загрузку, если удалите виртуальное ключевое слово. Я убрал, но это не помогло. Также в контексте я прописал this.ChangeTracker.LazyLoadingEnabled = false; Но это тоже не помогло.

Я также много видел, где упоминается использование функции .Load (), которая может ускорить выполнение запроса, но я не совсем понял, как использовать его в моем случае.

ОБНОВЛЕНИЕ

Поскольку все советуют мне включить Newtonsoft. Json .ReferenceLoopHandling.Ignore I дай мой автозагрузку и файлы контекста. На самом деле, я уже включил это. Пока я не добавил это, я вообще не мог отправить ответ, и после того, как я добавил его, он начал приходить, как я указал (см. JSON ответ вверху).

Мой контекст:

    public DbSet<Machines> machines{ get; set; }
    public DbSet<Characteristics> characteristics{ get; set; }
    public DbSet<Wheels> wheels{ get; set; }
    public DbSet<Pilot> pilot{ get; set; }

    public dbContext(DbContextOptions<dbContext> options) : base(options)
    {
        this.ChangeTracker.LazyLoadingEnabled = false;
    }

Мой стартап:

public void ConfigureServices(IServiceCollection services)
{
   ...

   services.AddDbContext<dbContext>(options => { 

        options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), 
        builder =>
        {
            builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
        });
        }); 

        services.AddControllers().AddNewtonsoftJson(x =>
 x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

}

Ответы [ 2 ]

2 голосов
/ 13 февраля 2020

Для asp. net core 2.x вы можете использовать следующий код в Startup.cs:

services.AddMvc().AddJsonOptions(options => 
         options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

Для asp. net core 3.x, сначала вам нужно установить Microsoft.AspNetCore.Mvc.NewtonsoftJson, а затем использовать следующий код:

services.AddMvc().AddNewtonsoftJson(options=> 
         options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
0 голосов
/ 12 февраля 2020

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

public virtual ICollection<Characteristics> characteristics{ get; set; }
public int MachineId { get; set; }
[ForeignKey("MachineId")]
public virtual Machines machine{ get; set; }
...