Есть ли способ настроить поведение запросов объектов по умолчанию?

У меня две таблицы, а одна - саморегуляция:

Job (id, description)
JobAssembly (id, jobid, parentassemblyid)

У меня есть два объекта домена аналогичным образом:

public class Job
{
 public int Id { get; set; }
 public string Description { get; set; }

 public virtual List<jobassembly> Assemblies { get; set; }
}

public class JobAssembly
{
 public int Id { get; set; }

 public int JobId { get; set; }
 public virtual Job { get; set; }

 public int? ParentAssemblyId { get; set; }
 public virtual JobAssembly ParentAssembly { get; set; }

 public virtual List<jobassembly> SubAssemblies { get; set; }
}
</jobassembly></jobassembly>

Вот проблема. Когда я использую EF:

using (var db = new JobContext())
{
 var job = db.Jobs.Find(1);
}

Я получаю, как ожидалось, задание. Но он поставляется со ВСЕМИ собраниями, а не только с родителями, а с узлами. Опять же, это ожидается.

Мой вопрос: как я могу обучить EF только приносить в JobAssemblies, которые не имеют подсетей... как поведение по умолчанию? Я знаю, как запросить EF для указанных родительских сборок. Но есть ли способ установить сопоставления или каким-либо другим способом, чтобы установить поведение запроса по умолчанию, чтобы получить только сборки, чей родительский сборник == null?

Благодаря :)

РЕДАКТИРОВАТЬ:

Позвольте мне проиллюстрировать:

У меня есть Job с id = 1. У него есть одна сборка с id = 1. Сборка 1 имеет две подсхемы с идентификаторами = 2 и 3 соответственно. Когда выполняется var job = db.Jobs.Find(1), EF заполняет граф объекта так:

У задания есть все три сборки (потому что jobid на всех трех == 1). JobAssembly с идентификатором 1 имеет соответствующие подмножества.

Все это ожидается, но было бы неплохо, если бы я мог настроить, как EF загружает объекты. Job не должен иметь каждого JobAssembly, где JobId == 1, но только там, где JobId == 1 и ParentAssemblyId == null.

2 ответа

Если я правильно понимаю, вы хотите, чтобы Job.Assemblies содержала только те сборки, у которых нет родителя (т.е. Те сборки, которые являются прямыми дочерьми задания, а не внуками и т.д.).

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

Мне кажется, что таблица Ассемблеров была создана таким образом, чтобы оптимизировать чтение данных (т.е. Вам нужно только один раз запросить запрос на JobId, тогда вы можете создать древовидную структуру в памяти). Я собираюсь предположить, что дело, а не говорит вам изменить структуру базы данных. Если это не так, дайте мне знать.

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

public class Job
{
 public int Id { get; set; }
 public string Description { get; set; }

 public virtual List<jobassembly> Assemblies { get; set; }

 public IEnumerable<jobassembly> DirectChildren
 {
 get
 {
 return this.Assemblies == null
 ? null
 : this.Assemblies.Where(x => x.ParentAssemblyId == null);
 }
 }
}
</jobassembly></jobassembly>

но если вы собираетесь использовать этот подход, вам нужно быть действительно очень осторожным, чтобы вы не лениво загружали данные глупо. Некоторые люди, столкнувшись с проблемой, думают: "Я знаю, я буду использовать O/RM". Теперь у них проблемы с N + 1;)

Более надежным решением было бы использовать отдельный ViewModel для инкапсуляции древовидной структуры, требуемой в вашем уровне приложения. Это предотвращает выбор N + 1, потому что ваш уровень данных берет на себя ответственность за вытягивание всего списка ассемблий в одном запросе, а затем сопоставляет их с деревом для вашего уровня приложения:

public class JobViewModel
{
 public int Id { get; set; }
 public string Description { get; set; }

 public virtual List<jobassemblyviewmodel> Children { get; set; }
}

public class JobAssemblyViewModel
{
 public int Id { get; set; }

 public virtual List<jobassemblyviewmodel> Children { get; set; }
}
</jobassemblyviewmodel></jobassemblyviewmodel>

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


Здесь идея, использующая наследование для различения RootAssemblies и SubAssemblies:

public abstract class JobAssembly
{
 public int Id { get; set; }

 public virtual List<subassembly> SubAssemblies { get; set; }
}

public class SubAssembly : JobAssembly
{
 public int ParentAssemblyId { get; set; }

 public virtual JobAssembly ParentAssembly { get; set; }
}

public class RootAssembly : JobAssembly
{
 public int JobId { get; set; }

 public virtual Job Job { get; set; }
}

public class Job
{
 public int Id { get; set; }

 public string Description { get; set; }

 public virtual List<rootassembly> Assemblies { get; set; }
}
</rootassembly></subassembly>

licensed under cc by-sa 3.0 with attribution.