Лучший способ справиться с круговыми ссылками? - EF Core 3.1 и веб-API - PullRequest
0 голосов
/ 07 марта 2020

В настоящее время я пытаюсь перейти на EF Core со значением один-ко-многим (у user есть много items). Учебное пособие или три позже мне удалось заставить вещи работать с двумя очень маленькими и простыми таблицами; однако я получил исключение json: A possible object cycle was detected which is not supported, которое указывало, что у меня были циклические ссылки.

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

Пользователь:

namespace TestWebApplication.Database
{
    public class User
    {
        [Key]
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Dob { get; set; }
        public string Location { get; set; }
        public ICollection<Items> Items { get; set; }
    }
} 

Элементы:

namespace TestWebApplication.Database
{
    public class Items
    {
        [Key]
        public int ItemId { get; set; }
        public string Item { get; set; }
        public string Category { get; set; }
        public string Type { get; set; }
        public virtual User User { get; set; }
    }
}

DtoItems:

namespace TestWebApplication.Database.DTOs
{
    public class DtoItems
    {
        public string Item { get; set; }
        public string Category { get; set; }
        public string Type { get; set; }
        public DtoUser User { get; set; }
    }
}

DtoUser:

namespace TestWebApplication.Database.DTOs
{
    public class DtoUser
    {
        public string UserName { get; set; }
        public string Dob { get; set; }
        public string Location { get; set; }
    }
}

TestController:

[HttpGet]
[Route("getitems")]
public ActionResult<List<Items>> GetItems()
{
    List<Items> items = _myContext.Items.Include(i => i.User).ToList();

    // DTOs
    List<DtoItems> dtoItems = new List<DtoItems>();

    foreach (var i in items)
    {
        var dtoItem = new DtoItems
        {
            Item = i.Item,
            Category = i.Category,
            Type = i.Type,
            User = new DtoUser
            {
                UserName = i.User.UserName,
                Dob = i.User.Dob,
                Location = i.User.Location
            }
        };

        dtoItems.Add(dtoItem);
    }

    return Ok(dtoItems);
}

Выход из конечной точки:

[
    {
        "item": "xxx",
        "category": "xxx",
        "type": "xxx",
        "user": {
            "userName": "xxx",
            "dob": "xxx",
            "location": "xx"
        }
    },
    {
        "item": "xxx",
        "category": "xxx",
        "type": "xxx",
        "user": {
            "userName": "xxx",
            "dob": "xxx",
            "location": "xxx"
        }
    }
]

1 Ответ

1 голос
/ 15 марта 2020

По моему мнению, использование DTO - правильный способ решения этой проблемы. Тот факт, что ваша модель данных не сериализуется должным образом, пытается намекнуть вам, что вам вообще не следует сериализовать вашу модель данных из API.

Я думаю, что возвращение DTO также решает дальнейшие проблемы в будущем (что, если вы хотите вернуть все свойства UserModel, кроме одного, возможно, это чувствительное свойство, которое вы не хотите просто возвращать из своего API, Что если ваша UserModel в БД получит больше свойств навигации, которые вы не хотите возвращать?).

На самом деле есть только два способа справиться с этим.

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

Примерно так:

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

System.Text. Json не имеет поддержки для этого (пока). Следуйте этой проблеме Github для получения дополнительной информации: https://github.com/dotnet/runtime/issues/30820

  • Вы используете атрибут JsonIgnore, чтобы принудительно не сериализовать свойства, которые будут работать, но ... Это выглядит странно, что Модель EntityFramework имеет JSON опций сериализации ...

Так что ваш лучший выбор - придерживаться DTO.

Дополнительная информация:

...