#c# #linq #entity-framework #linq-to-entities
#c# #linq #entity-framework #linq-to-entities
Вопрос:
У меня есть следующий граф объектов:
Root (Root_Id)
—- Дочерний элемент (Child_Id, Root_Id)
—— Внук (GrandChild_Id, Child_Id)
И я хочу обойти дочернюю и вернуть коллекцию внуков, имеющую корневой объект. До сих пор я пробовал это:
var child_Ids = db.Root
.SingleOrDefault( r => r.Root_Id == rootID )
.Childs
.Select( ch => new { Child_Id = ch.Child_Id} ).ToArray();
return db.GrandChilds.Where( gc => child_Ids.Contains( gc.Child_Id ) );
Но это даже не будет компилироваться со следующими ошибками :
1) IEnumerable не содержит определения для Contains …
2) Экземпляр аргумента: не удается преобразовать из ‘AnonymousType # 1 []’ в ‘System.Linq.IQueryable
Как я могу это сделать?
Ответ №1:
db.Root
.SingleOrDefault( r => r.Root_Id == rootID )
.Childs.SelectMany(ch=>ch.GrandChilds).Distinct()
Используйте .SelectMany
расширение для получения коллекции внуков
Комментарии:
1. В чем ошибка компиляции? Имя свойства может отличаться
Ответ №2:
Попробуйте это
var child_Ids = db.Root
.SingleOrDefault( r => r.Root_Id == rootID )
.Childs
.Select( ch => ch.Child_Id)
.ToArray();
return
from grandChild in db.GrandChild
join child_id in child_Ids
on child_id == grandChild.HandlingUnit_Id
select grandChild;
P.S: Я все еще немного не уверен в вашей цели, но это похоже на рабочее приближение вашего первоначального решения
Редактировать:
Если ваша иерархия и классы представляют собой что-то вроде:
public class Db
{
public Db(IEnumerable<Root> roots)
{ this.Roots = new List<Root>(roots); }
public ICollection<Root> Roots { get; private set; }
}
public class Root
{
public Root(IEnumerable<Child> children )
{
this.Children = new List<Child>(children);
}
public ICollection<Child> Children { get; private set; }
}
public class Child
{
public Child(Int32 childId, Int32 rootId, IEnumerable<GrandChild> grandChildren)
{
this.Child_Id = childId;
this.Root_Id = rootId;
this.GrandChildren = new List<GrandChild>(grandChildren);
}
public Int32 Child_Id { get; private set; }
public Int32 Root_Id { get; private set; }
public ICollection<GrandChild> GrandChildren {get; private set;}
}
public class GrandChild
{
public GrandChild (Int32 grandChildId, Int32 childId)
{
this.GrandChild_Id = grandChildId;
this.Child_Id = childId;
}
public Int32 GrandChild_Id {get; private set;}
public Int32 Child_Id {get; private set;}
}
Затем, как это уже было предложено AD.NET вы могли бы попробовать метод SelectMany
GrandChild gc1 = new GrandChild(1, 10);
GrandChild gc2 = new GrandChild(2, 10);
GrandChild gc3 = new GrandChild(3, 11);
Child c1 = new Child(10, 100, new GrandChild[]{ gc1, gc2 });
Child c2 = new Child(11, 100, new GrandChild[]{ gc3 });
Root r1 = new Root(new Child[]{c1, c2});
Db db = new Db(new Root[] { r1 });
var rootGrandChildren = db
.Roots
.FirstOrDefault()
.Children
.SelectMany(child => child.GrandChildren);
В синтаксисе запроса это будет выглядеть так
var rootGrandChildren = from child in db.Roots.FirstOrDefault().Children
from grandChild in child.GrandChildren
select grandChild;
Но если ваш Child
класс не знает своих внуков, и они (внуки) содержатся в Root:
public class Child
{
public Child(Int32 childId, Int32 rootId)
{
this.Child_Id = childId;
this.Root_Id = rootId;
}
public Int32 Child_Id { get; private set; }
public Int32 Root_Id { get; private set; }
}
public class Root
{
public Root(IEnumerable<Child> children, IEnumerable<GrandChild> grandChildren )
{
this.Children = new List<Child>(children);
this.GrandChildren = new List<GrandChild>(grandChildren );
}
public ICollection<Child> Children { get; private set; }
public ICollection<GrandChild> GrandChildren{ get; private set; }
}
вам нужно будет использовать:
Root r1 = new Root(new Child[]{c1, c2}, new GrandChild[]{gc1, gc2, gc3});
Db db = new Db(new Root[] { r1 });
Root root = db.Roots.FirstOrDefault();
var rootGrandChildren = from child in root.Children
join grandChild in root.GrandChildren
on child.Child_Id equals grandChild.Child_Id
select grandChild;
Комментарии:
1. Цель состоит в том, чтобы получить коллекцию внуков, имеющих корневого родителя, мне не нужна коллекция дочерних элементов для моего варианта использования. Я попробую ваше предложение и дам вам знать.
2. Но что такое gc.HandlingUnit_Id в вашем исходном примере?
3. извините, должно быть, это была опечатка. (возвращает db. Внуки. Где( gc => child_Ids.Contains( gc.Child_Id ) );). Я обновил вопрос, чтобы отразить это