Возврат данных EF Core в методе

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

  public List<Address> GetAddress()
    {
        using (var db = new CrmDbContext())
        {
            var address = from a in db.Addresses
                          join City in db.Cities on a.CityId equals City.CityId
                          join Area in db.Areas on a.AreaId equals Area.AreaId
                          select a;
  
            List<Address> result = address.ToList();
            return result;
        }
    }

Если я вывожу так:

foreach(var address in addressModel.GetAddress())
 {
     WriteLine(address.City.CityName);
 }

То у меня вылетает Ecxeption

System.NullReferenceException: "Object reference not set to an instance of an object."

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


Ответы (2 шт):

Автор решения: Faraday

Почему вы не хотите использовать методы Linq? Для примера, представим, что у вас есть таблица UserEntity:

public int Id { get; set; }
public string Login { get; set; }

И таблица телефонов PhoneEntity:

public int Id { get; set; }
public string Phone { get; set; }

Объединим это всё связью один-ко-многим. UserEntity:

public int Id { get; set; }
public string Login { get; set; }

public ICollection<PhoneEntity> Phones { get; set; }

И сам телефон PhoneEntity:

public int Id { get; set; }
public string Phone { get; set; }

public int UserId { get; set; }
public UserEntity User { get; set; }

Как теперь это всё вытянуть и привязать к UserEntity все его телефоны PhoneEntity:

var users = _dbContext.Users.Include(user => user.Phones).ToList();

Тут мы используем .Include(), который аналогичный использованию LEFT JOIN

Далее представим, что у вас к телефону ещё привязана книга контактов (PhoneEntity -> ContactEntity как one-to-many), тогда запрос, который объеденит это всё будет выглядеть вот так:

var users = _dbContext.Users
    .Include(user => user.Phones)
        .ThenInclude(phone => phone.Contacts)
    .ToList();

Далее для примера, мы можем изменить нашего UserEntity сделующим образом:

public int Id { get; set; }
public string Login { get; set; }

public ICollection<PhoneEntity> Phones { get; set; }
public ICollection<DocumentEntity> Documents { get; set; }

Как нам вытянуть все данные вместе? Вот так:

var users = _dbContext.Users
    .Include(user => user.Phones)
        .ThenInclude(phone => phone.Contacts)
    .Include(user => user.Documents)
    .ToList();

Далее всё по аналогии. Это замечательная аналогия тому, что вы хотите.

P.S.: Я не писал прямой ответ на ваш вопрос, а лишь предоставил информацию для того, что бы вы разобрались с этими понятиями и смоги самостоятельно выучить этот материал и решить задачу

UPD: если вы хотите сделать выборку, используйте метод .Where(), вот пример использования для последнего примера кода:

var users = _dbContext.Users
    .Where(user => user.Id > 100)
    .Include(user => user.Phones)
        .ThenInclude(phone => phone.Contacts)
        .Where(phone => phone.Phone != "1234567890")
    .Include(user => user.Documents)

    .ToList();
→ Ссылка
Автор решения: CrazyElf

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

Но, насколько я понял из ответа на английском СО, Include можно использовать и с вашим sql-стилем запросов. Так должно сработать:

var address = (from a in db.Addresses
              join City in db.Cities on a.CityId equals City.CityId
              join Area in db.Areas on a.AreaId equals Area.AreaId
              select a).Include("City");
                       ^^^^^^^^^^^^^^^^ загружаем в поле связанные значения

→ Ссылка