Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Работа с коллекциями


Автор: greef 31.1.2008, 21:26
Не могу найти ошибку в след коде. Цель: получив id объектов извне (по этим id можно найти объекты), засунуть потом эти объекты в List.
Код

            ArrayList listFreinds = new ArrayList();

            int sizeListFriend;
            sizeListFriend = cc.getViewuser().getFriendlist().size(); 

            for(int i=0; i<=sizeListFriend; i++){
                String idFriend = (String) cc.getViewuser().getFriendlist().get(i);

                listFreinds.add(userManager.getUser(idFriend));
            }
            u.setFriendlist(listFreinds);

            userManager.saveUser(u);


cc.getViewuser().getFriendlist() - массив id-ков приходящий извне. Те тут будет 1, 4, 15 etc
cc.getViewuser().getFriendlist().get(i); - тут получаю эти id-ники
listFreinds.add(userManager.getUser(idFriend)); - а тут заполняю listFreinds объектами класса User имеющие id: 1, 4, 15 etc


Автор: Kangaroo 31.1.2008, 21:36
greef, 
а какая ошибка? Случайно не ArrayOutOfBound иксепшн?

Автор: v2v 31.1.2008, 22:59
Цитата(greef @  31.1.2008,  21:26 Найти цитируемый пост)
for(int i=0; i<=sizeListFriend; i++){

||
\/
Код

 for(int i=0; i<sizeListFriend; i++){

?

Автор: greef 1.2.2008, 01:01
Да, спасибо. Ошибка ArrayOutOfBound, а решением было 
Код

for(int i=0; i<sizeListFriend; i++)


Только теперь ошибок нет. Но сохранение друзей не происходит. 
Хотя остальные поля объекта сохраняются успешно.
Код

            u.setId(cc.getViewuser().getId());
            u.setName(cc.getViewuser().getName());
            .........
            ArrayList listFreinds = new ArrayList();

            int sizeListFriend;
            sizeListFriend = cc.getViewuser().getFriendlist().size();

            for(int i=0; i<sizeListFriend; i++){
                String idFriend = (String) cc.getViewuser().getFriendlist().get(i);

                listFreinds.add(userManager.getUser(idFriend));
            }
            u.setFriendlist(listFreinds);
            userManager.saveUser(u);

Те изменения в поле Name и тд, сохраняются успешно. А listFreinds нет.
Может проблему в маппинге?
Код

    <class name="org.gritsik.model.User" table="User" lazy="false">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name" not-null="true"/>
        ............
        <bag name="friendlist" cascade="all" inverse="true" lazy="false">
            <key column="user_id"/>
            <many-to-many column="friend_id" class="org.gritsik.model.User"/>
        </bag>
    </class>

Модель User
Код

public class User extends BaseObject {
    private Long id;
    private String name;
    ...........
    private List friendlist;


Добавлено через 9 минут и 44 секунды
Поспешил с вопросом smile 
inverse="true" убрал и все сохраняется.

Вот тут вопрос. Какое значени и в каких случаях надо использовать 
1) inverse="true"
2) cascade="all"
Документация не дала полного ответа. 

Заранее спасибо

Автор: LSD 1.2.2008, 15:21
Цитата(greef @  1.2.2008,  01:01 Найти цитируемый пост)
Вот тут вопрос. Какое значени и в каких случаях надо использовать 
1) inverse="true"
2) cascade="all"
Документация не дала полного ответа. 

Документация даёт полный ответ, просто надо её повнимательней читать smile 
Параметр inverse отвечает за то, по какому объекту будет определяться наличие связи между двумя сущностями. Пусть есть сущность А и Б, если у сущности А выставить параметр inverse в false, то наличие ссылки в А на Б будет означать, что связь есть (и сохранять её в базу). Если у А выставить inverse в true, то наличие связи будет определяться по Б.

Параметр cascade определяет какие операции будут применяться и к связанным сущностям. Если стоит "all", то все операции (сохранение, загрузка, удаление и т.п.) будут применяться и к связанным сущностям.

Автор: greef 2.2.2008, 16:57
LSD Спасибо.

Есть еще вопрос по коллекции.
Код

            for(int i=0; i<newFriends.size(); i++){
                User tempUser = (User) newFriends.get(i);
                List tempFriends = tempUser.getFriendlist();
                if(!tempFriends.contains(ourUser)){
                    tempFriends.remove(ourUser);
                    tempFriends.add(ourUser);
                    tempUser.setFriendlist(tempFriends);
                    userManager.saveUser(tempUser);
                }

Я должен добавить в список друзей юзеров - выбранного юзера (ourUser), соответственно если он там уже есть его добавлять не надо. Поэтому я перебираю всех юзеров tempUser и просматриваю список друзей этих юзеров tempFriends - если этот список содержит выбранного юзера, то ничего не делаю. Иначе добавляю.
Но у меня он добавляются еще и еще - таким образом получаю что в друзьях у юзеров будет повторятся выбранный юзер.


Автор: Platon 2.2.2008, 17:03
Я честно сказать, не сильно уверено, но может быть тебе корректно задать equals и hashCode?

Автор: LSD 2.2.2008, 22:19
Цитата(greef @  2.2.2008,  16:57 Найти цитируемый пост)
Я должен добавить в список друзей юзеров - выбранного юзера (ourUser), соответственно если он там уже есть его добавлять не надо. Поэтому я перебираю всех юзеров tempUser и просматриваю список друзей этих юзеров tempFriends - если этот список содержит выбранного юзера, то ничего не делаю. Иначе добавляю.
Но у меня он добавляются еще и еще - таким образом получаю что в друзьях у юзеров будет повторятся выбранный юзер.

Ничего не понял.

Автор: greef 2.2.2008, 23:02
Есть список людей. У каждого есть друзья. 
Вот я беру одного человека. И в список его друзей могу кого-то добавить (из имеющихся людей), кого-то удалить (из ранее выбранных друзей). Те работаю со списком друзей для определенного человека.
НО если я, например, у Иванова в друзьях был Сидоров. И после изменения я оставил его в друзьях, то он у меня еще раз добавляется хотя по идеи if(!tempFriends.contains(ourUser)) не должно это позволить.

Автор: Kangaroo 2.2.2008, 23:11
Опять непонятно  smile 
И еще, объясните, пожалуйста, смысл этих строчек:
Код

tempFriends.remove(ourUser);
tempFriends.add(ourUser);

?
Зачем его удалять, если потом сразу его же добавлять...

Автор: greef 2.2.2008, 23:34
Цитата

И еще, объясните, пожалуйста, смысл этих строчек

За это сорри. Просто пробовал разл варианты. Забыл удалить smile 

Хорошо тогда объясню по другому. 
Проблема - в коллекию добавляется объект даже если он в ней есть. Получается что у Иванова может получится 10 Сидоров в друзьях.
Описание - Из view приходит инфа от юзере. Имя, пол, список его друзей (checkbox). В онсабмит я сохраняю изменения.
Сначало все поля  типа имени, адреса ид (ourUser.setName(cc.getViewuser().getName());         ourUser.setLocation(cc.getViewuser().getLocation());).
Потом мне нужно сохранить список друзей - ourUser.setFriendlist(tmpList);. Для этого я и проделываю такую операцию. Если можете посоветовать другой вариант решения проблемы, буду очень благодарен.
Привожу пример контролера, модели, маппинга и команд класса.

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

    public ModelAndView onSubmit(HttpServletRequest request,
                                 HttpServletResponse response, Object command,
                                 BindException errors)
    throws Exception {
        if (EditFormController.log.isDebugEnabled()) {
            EditFormController.log.debug("entering 'onSubmit' method...");
        }

        UserFormCC cc  = (UserFormCC) command;

        if (request.getParameter("delete") != null) {
            userManager.removeUser(cc.getViewuser().toString());

        } else {
            User ourUser = cc.getViewuser();

            ourUser.setId(cc.getViewuser().getId());
            ourUser.setName(cc.getViewuser().getName());
            ourUser.setLocation(cc.getViewuser().getLocation());
            ourUser.setSex(cc.getViewuser().getSex());
            ourUser.setDay(cc.getViewuser().getDay());
            ourUser.setMonth(cc.getViewuser().getMonth());
            ourUser.setYear(cc.getViewuser().getYear());

            List allUsers = userManager.getUsersGroup();//cc.getViewusers();
            List newFriends = new ArrayList();
            List newIdFriends = cc.getViewuser().getFriendlist();
            for(int i=0; i<newIdFriends.size(); i++){
                String idFriend = (String) newIdFriends.get(i);
                User tempUser = userManager.getUser(idFriend);
                newFriends.add(tempUser);
            }

            /*---удаляем нашего юзера из списка друзей у всех юзеров---*/
            for(int i=0; i<allUsers.size(); i++){
                User tempUser = (User) allUsers.get(i);
                List tempFriends = tempUser.getFriendlist();
                tempFriends.remove(ourUser);
                tempUser.setFriendlist(tempFriends);
                userManager.saveUser(tempUser);
            }

            /*---добавляем нашего юзера в список друзей новых друзей---*/
            for(int i=0; i<newFriends.size(); i++){
                User tempUser = (User) newFriends.get(i);
                List tempFriends = tempUser.getFriendlist();
                if(!tempFriends.equals(ourUser)){
                    tempFriends.add(ourUser);
                    tempUser.setFriendlist(tempFriends);
                    userManager.saveUser(tempUser);
                }
            }

            List tmpList = ourUser.getFriendlist();
            tmpList.clear();
            tmpList.addAll(newFriends);
            ourUser.setFriendlist(tmpList);
            userManager.saveUser(ourUser);
        }

        return new ModelAndView(getSuccessView());
    }


Model
Код

public class User extends BaseObject {
    private Long id;
    private String name;
    private String location;
    private String sex;
    private String day;
    private String month;
    private String year;
    private List friendlist;


Mapping
 
Код

   <class name="org.gritsik.model.User" table="User" lazy="false">

        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name" not-null="true"/>
        <property name="location" column="location" not-null="true"/>
        <property name="sex" column="sex" not-null="true"/>
        <property name="day" column="day" not-null="true"/>
        <property name="month" column="month" not-null="true"/>
        <property name="year" column="year" not-null="true"/>

        <bag name="friendlist" lazy="false">
            <key column="user_id"/>
            <many-to-many column="friend_id" class="org.gritsik.model.User"/>
        </bag>
    </class>


Command class
Код

public class UserFormCC {
    private User viewuser;
    private List viewusers;

Автор: nornad 3.2.2008, 00:58
greef, тебе уже посоветовали решение - перегрузи в своём классе equals и hashCode и будет тебе счастье. Корректно перегрузи только.

Добавлено через 1 минуту и 47 секунд
Просто, у тебя в коллекции при проверке на наличие юзверя происходит сравнение по ссылкам, а ссылки могут быть разными. Сравнивать же надо у тебя данные, а их расположение в памяти. smile

Автор: nornad 3.2.2008, 16:10
Смотрим javadoc по поводу того, как работает метод List.contains:
Цитата

contains

boolean contains(Object o)

    Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).

Вывод - если ссылки не нулевые, то надо сравнивать данные методом equals.
Рисуем себе equals:
Код

public class User extends BaseObject {
    private Long id;
    private String name;
    private String location;
    private String sex;
    private String day;
    private String month;
    private String year;
    private List friendlist;
...
  public boolean equals(Object obj) {
    if(this == obj) return true;
    if(null == obj) return false;
    if(null == this.id) {
      if(null != obj.id) return false;
    } else {
      if(!this.id.equals(obj.id)) return false;
    }
    return true;
  }
}

Так как у тебя идёт завязка на таблицу в базе, где есть идентификатор - этого для сравнения хватит (если ещё считать, что новая запись с тем же именем должна иметь другой индентификатор). То есть, уникальность организуется за счёт идентификаторов.

hashCode я перегружать не силён, да и данная перегрузка equals не оптимальна, так что будет неплохо, если знающие люди поправят и дополнят.

Автор: greef 3.2.2008, 16:58
Класс User extends BaseObject. А в BaseObject переопределены equals и hashCode.
Или я не так понял?

Код

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class BaseObject implements Serializable {
    public String toString() {
        return ToStringBuilder.reflectionToString(this,
                ToStringStyle.MULTI_LINE_STYLE);
    }

    public boolean equals(Object o) {
        return EqualsBuilder.reflectionEquals(this, o);
    }

    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }
}

Автор: nornad 3.2.2008, 18:51
По коду прям всё сразу стало ясно, как там происходит сравнение. Либо откопай код непосредственно сравнения, либо перегрузи и проверь.

Автор: nornad 3.2.2008, 20:09
Кстати, в моём иквалзе стоит ещё добавить if(!(obj instanceof User)) return false; (ну или вообще на точное соответствие классов проверять, если надо).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)