Как избежать извлечения реляционных объектов в рамках цикла реляционной ссылки с использованием Entity Framework?

#c# #ef-code-first #entity-framework-4 #lazy-loading #asp.net-apicontroller

#c# #ef-code-first #entity-framework-4 #отложенная загрузка #asp.net-apicontroller

Вопрос:

Я пытаюсь правильно спроектировать структуру метода контроллера Api со следующим объектом в качестве возвращаемого типа:

            var obj= new CustomObject
                    {
                        Id = a.Id,
                        stampleProperty= a.stampleProperty,
                        stampleProperty= a.stampleProperty2,
                        B= a.B,
                    };
  

Базовый сценарий состоит из двух объектов A и B, которые имеют отношение «Многие ко многим», как описано ниже:

введите описание изображения здесь

 public class A
{

   public int AId { get; set; }
   public string sampleProperty{ get; set; }        
   public string sampleProperty2{ get; set; }

   public virtual ICollection B { get; set; }
}

public class B
{

   public int BId { get; set; }
   public string sampleProperty3{ get; set; }        
   public string sampleProperty4{ get; set; }
   public int  ComyId { get; set; }

   public virtual ICollection A{ get; set; }
   public virtual Comy Comy{ get; set; }
}
  

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

Код, который я опробовал на контроллере, хотя он использует подход «ленивой загрузки», возвращает встроенные объекты типа A внутри каждого связанного объекта типа B.

 var a = db.A.FirstOrDefault(a => a.stampleProperty== stampleProperty);
var obj= new CustomObject
                    {
                        Id = a.AId,
                        sampleProperty= a.sampleProperty,
                        sampleProp= a.sampleProp,
                        B = a.B,
                    };
  

Возврат:

 {
 "AId": 
 "sampleProperty":
 "sampleProp":
 "B":[{
      "BId":
      "sampleProperty3":
      "sampleProperty4":
      "ComyId":
      "A":[ **REFERENCE LOOP**  ]
      "ComyId":
      "Comy":{}
     }]
}
  

Цель: объекты B без виртуальных свойств A.

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

Ответ №1:

Я бы предложил создать дополнительный пользовательский объект и сопоставить поля (либо вручную, либо с помощью фреймворка, подобного AutoMapper).

Применительно к вашему примеру это может выглядеть примерно так:

 public class CustomObjectA
{
    public int Id { get; set; }
    public string stampleProperty { get; set; }
    public string stampleProperty2 { get; set; }
    public CusomObjectB[] B { get; set; }
}

public class CustomObjectB
{
    public int BId { get; set; }
    public string sampleProperty3{ get; set; }        
    public string sampleProperty4{ get; set; }
    public int ComyId { get; set; }
}
  

И использование будет выглядеть следующим образом:

 var a = db.A.FirstOrDefault(a => a.stampleProperty== stampleProperty);

var obj= new CustomObjectA
{
    Id = a.AId,
    sampleProperty= a.sampleProperty,
    sampleProp= a.sampleProp,
    B = a.B.Select(b => new CustomObjectB
    {
        BId = b.BId,
        sampleProperty3 = b.sampleProperty3

        //etc...
    }).ToArray()
};
  

Не обязательно возвращать объекты базы данных прямо из API по такого рода причинам (наряду с некоторыми другими, например, вы можете не хотеть, чтобы третьи стороны, использующие ваш API, могли видеть каждое свойство в базе данных).

Общим термином для этого подхода является использование DTO (объекты передачи данных). Вот руководство от Microsoft, где они обсуждают это подробнее https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5 .

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

1. Примечание: опечатки оставлены намеренно, чтобы соответствовать примерам кода вопроса.