Подтвердить что ты не робот

Используйте Entity Framework, я хочу включить только первые дочерние объекты, а не child of child (sub of sub)

Используя Entity Framework, я хочу включить только первый уровень дочерних объектов, а не дочерних.

У меня есть эти два класса:

public class BusinessesTBL
{
    public string ID { get; set; }
    public string FirstName { get; set; }
    public string lastName { get; set; }

    public ICollection<OffersTBL> OffersTBLs { get; set; }
}

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

    public int CatId { get; set; }

    public string BusinessesTBLID { get; set; }
    public virtual BusinessesTBL BusinessesTBLs { get; set; }
}

Когда я пытаюсь привести все предложения в соответствии с полем CatId, мне также нужно возвращать значения BusitiesTBL, но метод также возвращает предложения снова для каждого объекта BuseriesTBL. Мой код:

public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
    db.OffersTBLs.Include(s => s.BusinessesTBLs);
}

Вы можете увидеть неправильный результат на: http://mycustom.azurewebsites.net/api/OffersApi/GetOffersTBLsCat/4

Как вы можете видеть, он возвращает все предложения по каждому бизнес-объекту, в то время как бизнес-объект по каждому предложению, и я хочу только возвращать предложения с его бизнес-объектом без предложения в Business obj.

Может ли кто-нибудь помочь, пожалуйста?

4b9b3361

Ответ 1

Это происходит потому, что Entity Framework выполняет привязку отношений, которая является процессом, который автоматически заполняет свойства навигации, когда объекты, которые там находятся, присутствуют в контексте. Таким образом, с круговыми ссылками вы можете бесконечно развернуть навигационные свойства, даже когда ленивая загрузка отключена. Сериализатор Json делает именно это (но, по-видимому, ему поручено иметь дело с круговыми ссылками, поэтому он не попадает в бесконечный цикл).

Трюк заключается в том, чтобы предотвратить зависание отношений. Исправление отношений зависит от контекста ChangeTracker, который кэширует объекты для отслеживания их изменений и ассоциаций. Но если нечего отследить, там ничего не исправить. Вы можете остановить отслеживание, вызвав AsNoTracking():

db.OffersTBLs.Include(s => s.BusinessesTBLs)
             .AsNoTracking()

Если кроме того вы также отключите ленивую загрузку в контексте (установив contextConfiguration.LazyLoadingEnabled = false), вы увидите, что в строку Json заселяются только OffersTBL.BusinessesTBLs и что BusinessesTBL.OffersTBLs - пустые массивы.

Бонус в том, что AsNoTracking() увеличивает производительность, потому что трекер изменений не занят, отслеживая все объекты, которые EF материализуется. Фактически, вы всегда должны использовать его в отключенной настройке.

Ответ 2

Вы отключили ленивую загрузку на OffersTBL, сделав ее не виртуальной. Что делать, если вы активируете ленивую загрузку? например:

public class BusinessesTBL
{
    public string ID { get; set; }
    public string FirstName { get; set; }
    public string lastName { get; set; }

    //put a virtual here
    public virtual ICollection<OffersTBL> OffersTBLs { get; set; }
}

Затем, когда вы сериализуете, обязательно не вызывайте/не включайте OffersTBL. Если OffersTBL все еще возвращаются, это происходит потому, что вы извлекаете их где-нибудь в своем коде. Если это происходит, отредактируйте свой вопрос и вставьте весь код, включая логику сериализации.

Ответ 3

Так как OffersTBL имеет связь с BusinessesTBL и BusinessesTBL с предложениями TBL, вы можете бесконечно бросать объекты, такие как OffersTBL.BusinessesTBL.OffersTBL.BusinessesTBL и т.д.

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

Для BusinessTBL

public class BusinessesTBLHelper
{
    private BusinessesTBLHelper(BusinessesTBL o){
        ID = o.ID;
        FirstName = o.FirstName;
        lastName = o.LastName;
        OffersTBLids = new List<int>();

        foreach(OffersTBL offersTbl in o.OffersTBLs){
            OffersTBLids.Add(offersTbl.ID);
        }
    }

    public string ID { get; set; }
    public string FirstName { get; set; }
    public string lastName { get; set; }

    public IEnumerable<int> OffersTBLids { get; set; } //no references anymore
}

И то же самое для вашего объекта OffersTBL.

public class OffersTBLHelper
{
    private OffersTBLHelper(OffersTBL o){
        ID = o.ID;
        Name = o.Name;
        CatId = o.CatId;
        BusinessesTBLID = o.BusinessesTBLID;
        BusinessesTBLs = new BusinessesTBLHelper(o.BusinessesTBLs);
    }

    public string ID { get; set; }
    public string Name{ get; set; }
    public intCatId{ get; set; }

    public string BusinessesTBLID { get; set; }
    public BusinessesTBLHelper BusinessesTBLs { get; set; }
}

В запросе базы данных вы можете напрямую создавать новые helperobjects из queryresult:

public IEnumerable<OffersTBLHelper> GetOffersTBLsCat(int id)
{
    return db.OffersTBLs.where(s => s.CatId == id).Select(x=> new OffersTBLHelper(x)).ToList();
}

Теперь у вас есть все OfferTBL с BusinessesTBL под. Цикл останавливается здесь, потому что у BusinessesTBL нет под ним объявлений. Однако для дальнейших ссылок и идентификации они содержат только идентификаторы в списке.

Ответ 4

Предполагая, что объект isnt null и просто пуст:

 public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
 {
     db.OffersTBLs.Include(s => s.BusinessesTBLs).Where(x => !x.BusinessesTBLs.OffersTBLs.Any());
 }

Изменить: Фильтр перед включением:

public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
     db.OffersTBLs.Where(x => !x.BusinessesTBLs.OffersTBLs.Any())
         .Include(s => s.BusinessesTBLs);
}