Ответ 1
Это решение, которое требует только одного обратного перехода:
var orders = Context.Orders
.Select(o => new
{
Order = o,
SubOrderBases = o.SubOrderBases.Where(s => !(s is MyOrder)),
MyOrdersWithCustomers = o.SubOrderBases.OfType<MyOrder>()
.Select(m => new
{
MyOrder = m,
Customers = m.Customers
})
})
.ToList() // <- query is executed here, the rest happens in memory
.Select(a =>
{
a.Order.SubOrderBases = new List<SubOrderBase>(
a.SubOrderBases.Concat(
a.MyOrdersWithCustomers.Select(m =>
{
m.MyOrder.Customers = m.Customers;
return m.MyOrder;
})));
return a.Order;
})
.ToList();
Это в основном проекция в коллекцию анонимного типа. После этого результат запроса преобразуется в объекты и свойства навигации в памяти. (Он также работает с отключенным отслеживанием.)
Если вам не нужны сущности, вы можете пропустить всю часть после первого ToList()
и работать непосредственно с результатом анонимных объектов.
Если вы должны изменить этот граф объекта и потребовать отслеживания изменений, я не уверен, что этот подход безопасен, поскольку свойства навигации не полностью установлены при загрузке данных - например, MyOrder.Customers
- null
после проецирования а затем установление свойств отношений в памяти может быть обнаружено как модификация, которой она не является, и вызвать проблемы при вызове SaveChanges
.
Прогнозы выполняются для сценариев только для чтения, а не для модификаций. Если вам требуется отслеживание изменений, вероятно, более безопасный способ состоит в том, чтобы загружать полные объекты в несколько обращений, так как нет возможности использовать Include
в одном обратном переходе для загрузки всего графика объекта в вашей ситуации.