Стремительная загрузка включает в себя бесконечные таблицы самостоятельного объединения без таблиц включения - PullRequest
1 голос
/ 30 мая 2019

, когда я пытаюсь выбрать некоторые элементы, элементы приходят с их включениями, несмотря на то, что я не включил их объект в linq

public List<Institution> GetListWithCities(Expression<Func<Institution,bool>> filter = null)
{

   using (var context = new DbContext())
   {
    return filter == null 
           ? context.Set<Institution>()
                    .Include(x => x.City)
                    .ToList() 
           : context.Set<Institution>()
                    .Include(x => x.City)
                    .Where(filter)
                    .ToList();
  }
}

[Table("Institution")]
 public class Institution{
    public int ID;
    public string Name;
    public int CITY_ID;
    public int RESPONSIBLE_INSTUTION_ID;
    public virtual City City{ get; set; }
    public virtual Institution ResponsibleInstution{ get; set; }
}

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

1 Ответ

1 голос
/ 30 мая 2019

Люди склонны использовать Include вместо Select, хотя они не планируют использовать функциональность, предоставляемую Include, но все же тратят впустую вычислительную мощность, которую использует Include.

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

Одна из более медленных частей запроса к базе данных - это передача извлеченных данных из системы управления базами данных в ваш локальный процесс. Следовательно, разумно выбирать только те свойства, которые вы действительно планируете использовать.

По-видимому, ваш Institution находится точно в одном City, а именно City, на который ссылается внешний ключ (CityId?). Если Institution [10] находится в City [15], то Institution.CityId будет иметь значение 15, равное City.Id. Таким образом, вы передаете это значение дважды.

using (var dbContext = new MyDbContext())
{
    IQueryable<Institution> filteredInstitutions = (filter == null) ?
        dbContext.Institutions :
        dbContext.Institutions.Where(filter);
    return filteredInstitutions.Select(institution => new Institution
    {
        // Select only the Institution properties that you actually plan to use:
        Id = institution.Id,
        Name = institution.Name,

        City = new City
        {
            Id = institution.City.Id,
            Name = institution.City.Name,
            ...
        }

        // not needed: you already know the value:
        // CityId = institution.City.Id,
});

Возможное улучшение Очевидно, вы решили добавить слой между платформой сущностей и пользователями ваших функций: хотя они используют ваши функции, им не обязательно знать, что вы используете платформу сущностей для доступа к базе данных. Это дает вам свободу использовать SQL вместо сущности. Черт, это даже дает вам свободу избавиться от базы данных и использовать XML-файл вместо СУБД: ваши пользователи не почувствуют разницу: приятно, если вы захотите написать модульные тесты.

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

Рассмотрите возможность написания классов репозитория для Institution и City, которые предоставляют только те свойства, которые действительно нужны пользователям вашей персистентности. Если люди запрашивают только «некоторые свойства учреждений с некоторыми свойствами города, в котором они расположены», или наоборот «несколько свойств городов с несколькими свойствами учреждений, расположенных в этих городах», тогда им не понадобится внешние ключи.

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

Например: предположим, что вы добавили возможность удалить учреждение, но не хотите сразу удалять всю информацию об этом учреждении, например, потому что это позволяет вам восстановить, если кто-то случайно удалит учреждение, вы можете добавить обнуляемое свойство ObsoleteDate

Наибольшие люди, которые обращаются к учреждениям, не хотят устаревших учреждений. Если у вас был промежуточный класс учреждения хранилища, в котором вы пропустили ObsoleteDate, и все запросы удалили все Institutions, которые имеют ненулевое значение ObsoleteData, то для ваших пользователей это было бы так, как если бы устаревшее учреждение было бы удалено из базы данных.

Только одному пользователю потребуется доступ к ObsoleteDate: более чистой задаче, которая время от времени удаляет все Institutions, которые устарели в течение значительного времени.

Третье улучшение для промежуточного класса репозитория заключается в том, что вы можете предоставить разным пользователям доступ к одним и тем же данным с разными интерфейсами: некоторые пользователи могут только запрашивать информацию об учреждениях, некоторым также разрешается изменять некоторые данные, а другим разрешено изменять другие данные. Если вы дадите им интерфейс, они могут сломать его, вернув их в исходное учреждение.

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

Недостаток шаблона репозитория заключается в том, что вам приходится думать о разных пользователях и создавать разные функции запросов. Преимущество состоит в том, что хранилище легче менять и легче тестировать, и, следовательно, легче сохранять все ошибки без изменений после будущих изменений.

...