2012-06-12 1 views
3

Я просматривал поисковую систему и не нахожу ответа на мою проблему, хотя эти вопросы схожи, и я даже использовал некоторые из них, чтобы начать. вы попали в кирпичную стену.Сортировка IList <Person> по родительскому объекту, который может быть пустым

Я уже проверил эти вопросы

Я объект привезенные NHibernate называется Person следующим

public class Person : IPerson, IComparable<Person>{ 

    // private properties 
    private int _id; 
    private string _name; 
    private Person _parent; 
    private IList<Person> _children; 
    private IList<Group> _groups; 

    // public properties 
    public virtual int id 
    { 
     get { return _id; } 
     set { _id = value; } 
    } 

    public virtual string name 
    { 
     get { return _name; } 
     set { _name= value; } 
    } 

    public virtual Person Parent 
    { 
     get { return _parent; } 
     set { _parent = value; } 
    } 

    public virtual IList<Person> Children 
    { 
     get { return _children; } 
     set { _children = value; } 
    } 

    public virtual IList<Group> Groups 
    { 
     get { return _groups; } 
     set { _groups = value; } 
    } 

    // constructor 
    public Person() {} 

    // this section I added after looking on SO 
    public virtual Int32 parentid 
    { 
     get { 
      if (_parent == null) 
      { 
      return _id; 
      } else { 
      return _parent.id; 
      } 
     } 
    } 

    public virtual Int32 CompareTo(Person obj) 
    { 
     if (this.id == obj.id) 
      return 0; 
     return this.parentid.CompareTo(obj.parentid); 
    } 
} 

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

i.e. (id,name,parent) 
person 1 (1,"Alice",null) 
person 2 (2,"Bob",1) 
person 3 (3,"Charlie",null) 
person 4 (4,"Dejgo",2) // child of a child 
person 5 (5,"Edgar", null) 
person 6 (6,"Florence", 3) 

Когда я делаю вид, как упомянуто в этом answer как так:

class PeopleBLL : IPeopleBLL { 

    // spring properties 
    private IGroupsBLL _groupsBLL; 
    private IPeopleDao _peopleDao; 

    // public properties where spring sets up the links to the other dao and bll methods 
    public IGroupsBLL { 
     set{_groupsBLL = value;} 
    } 
    public IPeopleDao { 
     set{_peopleDao= value;} 
    } 

    // constructor 
    public PeopleBLL() 
    { 
    } 

    // method we are interested in 
    public IList<Person> GetAllInGroup(int groupID){ 
     //get the group object 
     Group groupObject = _groupsBLL.Get(groupID); 
     // get the people in the group 
     IList<Person> people = _peopleDao.GetAllInGroup(groupObject); 
     // do something here to sort the people 
     people.Sort(); 
     // return the list of people to aspx page 
     return people; 
    } 
} 

Я получаю список в формате

person 2 
person 1 
    person 6 
person 3 
person 5 
     person 4 

, но я хочу его в формате

person 1 
    person 2 
     person 4 
person 3 
    person 6 
person 5 

Любой идентификатор EAS?

EDIT:

Я не ставил остальную часть этого, потому что я не хочу, чтобы запутать вопрос всеми дополнительными технологиями, используемыми, но так как я был задан вопрос. Spring.Net используется для связывания всех объектов, у меня есть трехуровневая архитектура Front end (страницы asp.net), бизнес-уровень и уровень Dao, который взаимодействует с базой данных. Я обновил GetAllInGroup(), чтобы показать все, что он делает, но это только сортировка, в которой меня интересует. Дао использует запрос критерия nHibernate для получения всех объектов под группой следующим образом.

public IList<Person> getRegistrationsForDonor(Group groupObject) { 
     IList<Person> rv = CurrentSession.CreateCriteria(typeof(Person),"p") 
         .CreateCriteria("Groups","g") 
         .Add(Expression.Eq("g.id", groupObject.id)) 
         .List<Person>(); 
     return rv; 
    } 

И все это началось в странице ASPX в объекте источника данных

<asp:ObjectDataSource ID="ObjectDataSource1" OnObjectCreating="DataSource_ObjectCreating" runat="server" DataObjectTypeName="Domain.Person" TypeName="BusinessLayer.PersonBLL" DeleteMethod="delete" SelectMethod="GetAllInGroup" UpdateMethod="update"> 
    <SelectParameters> 
     <asp:ControlParameter ControlID="groupid" Type="Int32" DefaultValue="0" Name="groupID" /> 
    </SelectParameters> 
</asp:ObjectDataSource> 

, который затем используется в GridView, поэтому, к сожалению, я должен вернуться отсортированный IList из BLL на фронт end в BLL-методе как один IList.

Edit 2

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

person 2 (2,"Bob",1) 
person 4 (4,"Dejgo",2) // child of a child 
person 6 (6,"Florence", 3) 

, который я хотел бы надеяться, что вернется

person 2 
    person 4 
person 6 

Редактировать 3

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

Попытка @ jon-senchyna ответить в 17:30, я определенно приближаюсь, я только что попробовал это на некоторых живых данных, и это почти что есть, но я, кажется, сталкиваюсь с проблемами с детьми, родителей в группе. Возьмем следующий пример в первой группе: 48 человек, я выделим интересующие вас темы.

(789, "person 1", null) 
(822, "Person 34", null) 
(825, "Person 37", 789) 
(3060, "Person 47", 822) 
(3061, "Person 48", 825) 

Это порядок они возвращаются из базы данных, но когда они ставятся через то они в порядке

Person 48 - id: 3061 
Person 37 - id: 825 
Person 1 - id: 789 
Person 47 - id: 3060 
Person 34 - id: 822 

Так дети находятся рядом с родителями, но в обратном порядке в котором я бы хотел их в заказе

Person 1 - id: 789 
Person 37 - id: 825 
Person 48 - id: 3061 
Person 34 - id: 822 
Person 47 - id: 3060 
+0

Можете ли вы оставить остальную часть кода, чтобы получить четкое представление о том, что вы делаете в коде. – MMK

+0

С другой стороны, я бы удостоверился, что класс был сопоставлен для определения родительских отношений с дочерними элементами. Тогда я бы сделал что-то вроде «var q = from p в session.Query где p.parent == null order by p.name '. Тогда пусть NHibernate сделает все остальное. Не может быть плохой идеей переопределить CompareTo для использования имени или чего-то еще. – cloggins

+0

Просто случайная нота, вы пропустили точку с запятой после объявления '_parent', а ваш список' _children' должен быть типа 'Person', а не' person'. Я пытался сделать изменения, но SO жаловался, что я не chaneg не менее 6 символов ... –

ответ

2

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

public virtual Int32 CompareTo(Person person2) 
{ 
    Stack<Person> parents1 = GetParents(this); 
    Stack<Person> parents2 = GetParents(person2); 
    foreach (Person parent1 in parents1) 
    { 
     Person parent2 = parents2.Pop(); 
     // These two persons have the same parent tree: 
     // Compare their ids 
     if (parent1 == null && parent2 == null) 
     { 
      return 0; 
     } 
     // 'this' person's parent tree is contained in person2's: 
     // 'this' must be a parent of person2 
     else if (parent1 == null) 
     { 
      return -1; 
     } 
     // 'this' person's parent tree contains person2's: 
     // 'this' must be a child of person2 
     else if (parent2 == null) 
     { 
      return 1; 
     } 
     // So far, both parent trees are the same size 
     // Compare the ids of each parent. 
     // If they are the same, go down another level. 
     else 
     { 
      int comparison = parent1.id.CompareTo(parent2.id); 
      if (comparison != 0) 
      { 
       return comparison; 
      } 
     } 
    } 
    // We should never get here anymore, but if we do, 
    // these are the same Person 
    return 0; 
} 

public static Stack<Person> GetParents(Person p) 
{ 
    Stack<Person> parents = new Stack<Person>(); 
    // Add a null so that we don't have to check 
    // if the stack is empty before popping. 
    parents.Push(null); 
    Person parent = p; 
    // Recurse through tree to root 
    while (parent != null) 
    { 
     parents.Push(parent); 
     parent = parent.Parent; 
    } 
    return parents; 
} 

Update: Оба родителя-стеки теперь содержат оригинальный человек, что делает логику сравнения немного легче.

+0

Отличные они теперь в правильном порядке для первого уровня, но человек 4 (4, «Dejgo», 2) ребенок ребенка все еще является последней записью, есть ли у вас какие-либо идеи, которые нужно добавить, уровня. – kamui

+0

Я обновил свой ответ, чтобы обрабатывать несколько уровней вложенности. К сожалению, сейчас это много mroe complex, но дополнительные функции, такие как GetRoot и GetParents, могут быть полезны для других вещей, кроме сортировки. –

+0

После повторного ввода кода я смог удалить некоторую сложность. Многие строки - это просто комментарии. В целом вам нужно сравнить родительские деревья обоих объектов Person, а затем сравнить сами объекты Person, если они имеют одинаковые родительские деревья. –

0

Просто внимание: Вам не нужно загружать всех людей Если вы загружаете людей без родителя, вы получите 1, 3 и 5. И вы можете получить доступ к 2, 4 и 6 с помощью Children-property. Чтобы получить список всех 6 в этом порядке (без иерархии), вы можете пройти через 3 корневых узла рекурсивно и создать окончательный список.

+0

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

+0

Пожалуйста, см. Мое редактирование, так как они [Лицо] в [ Group], нет гарантии, что корневые элементы будут иметь родительский элемент null. – kamui

+0

Хорошо, это делает мое рассмотрение спорным. – Franky

 Смежные вопросы

  • Нет связанных вопросов^_^