【问题标题】:EF Core Customize JSON Serialization with LINQEF Core 使用 LINQ 自定义 JSON 序列化
【发布时间】:2020-02-19 20:12:11
【问题描述】:

我正在为 .NET Core 中的 API 构建一个演示,并构建一个嵌套的 JSON 对象,该对象需要通过一系列 LINQ 查询来构建。

我当前的问题是,当我得到大约 4 层深度时,我想自定义实际序列化的内容,更具体地说,我想专门为此查询“不包括”特定导航属性,但不是出于一般目的,仅对于这个特定的查询。

我的第一个想法是做一个 DTO,但这似乎是一个不必要的额外模型,仅针对这个特定情况......我想直接使用 LINQ 来处理我的结果。

我已经在我的 Startup.cs 文件中添加了以下内容以避免循环:

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

我目前有 5 个正在运行的模型,如下所示:

 public class Hotel
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string StreetAddress { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Phone { get; set; }
        public List<HotelRooms> HotelRooms { get; set; }
    }

    public class Room
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public Layout Layout { get; set; }

        public List<RoomAmenities> RoomAmenities { get; set; }
        public List<HotelRooms> HotelRooms { get; set; }
    }

    public class HotelRooms
    {
        public int HotelID { get; set; }
        public int RoomNumber { get; set; }
        public int RoomID { get; set; }
        public decimal Rate { get; set; }
        public bool PetFriendly { get; set; }
        public Hotel Hotel { get; set; }
        public Room Room { get; set; }
    }

    public class Amenities
    {
        public int ID { get; set; }
        public string Name { get; set; }

        // Navigation Properties
        public List<RoomAmenities> RoomAmenities { get; set; }
    }

    public class RoomAmenities
    {
        public int RoomID { get; set; }
        public int AmenitiesID { get; set; }

        public Room Room { get; set; }
        public Amenities Amenity { get; set; }
    }

在我的服务中,我有这个实际上是在做查询的逻辑:

        public async Task<Hotel> GetById(int id)
        {
            var hotel = await _context.Hotel.FindAsync(id);
            // Get a list of rooms
            var rooms = await _context.HotelRooms.Where(r => r.HotelID == id)
                                            .Include(d => d.Room)
                                            .ThenInclude(a => a.RoomAmenities)
                                            .ThenInclude(x => x.Amenity).ToListAsync();
            hotel.HotelRooms = rooms;

            return hotel;
        }

当前输出为:

{
    "id": 1,
    "name": "Amanda's Hotel",
    "streetAddress": "123 CandyCane Lane",
    "city": "Seattle",
    "state": "WA",
    "phone": "123-456-8798",
    "hotelRooms": [
        {
            "hotelID": 1,
            "roomNumber": 101,
            "roomID": 2,
            "rate": 75.00,
            "petFriendly": false,
            "room": {
                "id": 2,
                "name": "Queen Suite",
                "layout": 2,
                "roomAmenities": [
                    {
                        "roomID": 2,
                        "amenitiesID": 1,
                        "amenity": {
                            "id": 1,
                            "name": "Coffee Maker",
                            "roomAmenities": [
                                {
                                    "roomID": 1,
                                    "amenitiesID": 1,
                                    "room": {
                                        "id": 1,
                                        "name": "Princess Suite",
                                        "layout": 1,
                                        "roomAmenities": [
                                            {
                                                "roomID": 1,
                                                "amenitiesID": 2,
                                                "amenity": {
                                                    "id": 2,
                                                    "name": "Mini Bar",
                                                    "roomAmenities": []
                                                }
                                            }
                                        ],
                                        "hotelRooms": [
                                            {
                                                "hotelID": 1,
                                                "roomNumber": 123,
                                                "roomID": 1,
                                                "rate": 120.00,
                                                "petFriendly": true
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    }
                ],
                "hotelRooms": []
            }
        },
        {
            "hotelID": 1,
            "roomNumber": 123,
            "roomID": 1,
            "rate": 120.00,
            "petFriendly": true,
            "room": {
                "id": 1,
                "name": "Princess Suite",
                "layout": 1,
                "roomAmenities": [
                    {
                        "roomID": 1,
                        "amenitiesID": 1,
                        "amenity": {
                            "id": 1,
                            "name": "Coffee Maker",
                            "roomAmenities": [
                                {
                                    "roomID": 2,
                                    "amenitiesID": 1,
                                    "room": {
                                        "id": 2,
                                        "name": "Queen Suite",
                                        "layout": 2,
                                        "roomAmenities": [],
                                        "hotelRooms": [
                                            {
                                                "hotelID": 1,
                                                "roomNumber": 101,
                                                "roomID": 2,
                                                "rate": 75.00,
                                                "petFriendly": false
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "roomID": 1,
                        "amenitiesID": 2,
                        "amenity": {
                            "id": 2,
                            "name": "Mini Bar",
                            "roomAmenities": []
                        }
                    }
                ],
                "hotelRooms": []
            }
        }
    ]
}

这对我来说太嵌套了,我希望不包括“amenity”对象内的内部“roomAmenities”。我希望我的对象看起来像这样:

{
  "id": 1,
  "name": "Amanda's Hotel",
  "streetAddress": "123 CandyCane Lane",
  "city": "Seattle",
  "state": "WA",
  "phone": "123-456-8798",
  "hotelRooms": [
    {
      "hotelID": 1,
      "roomNumber": 101,
      "roomID": 2,
      "rate": 75,
      "petFriendly": false,
      "room": {
        "id": 2,
        "name": "Queen Suite",
        "layout": 2,
        "roomAmenities": [
          {
            "roomID": 2,
            "amenitiesID": 1,
            "amenity": {
              "id": 1,
              "name": "Coffee Maker"
            }
          }
        ],
        "hotelRooms": []
      }
    },
    {
      "hotelID": 1,
      "roomNumber": 123,
      "roomID": 1,
      "rate": 120,
      "petFriendly": true,
      "room": {
        "id": 1,
        "name": "Princess Suite",
        "layout": 1,
        "roomAmenities": [
          {
            "roomID": 1,
            "amenitiesID": 1,
            "amenity": {
              "id": 1,
              "name": "Coffee Maker"
            }
          },
          {
            "roomID": 1,
            "amenitiesID": 2,
            "amenity": {
              "id": 2,
              "name": "Mini Bar"
            }
          }
        ],
        "hotelRooms": []
      }
    }
  ]
}

有人对我如何使用 EFCore 和 LINQ 实现这一点有任何指导吗?

【问题讨论】:

  • >我的第一个想法是做一个 DTO 这是正确的方法。事实上,我几乎可以说,如果你能提供帮助,你不应该从你的 API 中真正返回 EF 模型(否则每次你更改数据模型时,你的 API 合同可能会在不需要时更改)。
  • 啊,谢谢!你绝对是对的,DTO 是最好的方法。
  • 您是否尝试过不将amenity 包含为var rooms = await _context.HotelRooms.Where(r =&gt; r.HotelID == id).Include(d =&gt; d.Room).ThenInclude(a =&gt; a.RoomAmenities).ToListAsync();

标签: c# json linq asp.net-core ef-core-3.0


【解决方案1】:

你可以查看这篇文章 What is the difference between PreserveReferencesHandling and ReferenceLoopHandling in Json.Net?

我看到你已经实现了referenceloopHandling,但是即使你在使用它,你也只能将内部引用设置为null,但不能完全从json中删除键值对

【讨论】:

    猜你喜欢
    • 2018-07-05
    • 1970-01-01
    • 2014-08-02
    • 2014-08-20
    • 1970-01-01
    • 2011-02-25
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多