Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Организация хранения дерева элементов с пом. JPA 
:(
    Опции темы
poulmart
Дата 23.2.2008, 00:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



Задача: Создать справочник элементов в виде дерева. (ну типа файловой системы единственно что элементы однотипные)

Решение: Создал два класса один (Spravochnik) отвечает за хранение элемента, второй (Association) за хранение связей между элементами.

Возникла такая проблема:

Т.к. справочников может быть несколько. то и пар классов должно быть столько же. И фактически в каждой паре дублируется код (ну типа setParent, gePArent, setChildren, getChildren  и т.д.).

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

P.S. Сильно не пинать. Только учусь

Код:


Spravochnik.java

Код

package entities;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;


/**
 *
 * @author poul
 */
@Entity
public class Spravochnik implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "kod", nullable = false, unique = true)
    private String kod;
    @Column(name = "name", nullable = false)
    private String name;
    @Column(name = "folder", nullable = false)
    private boolean folder;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
    private Collection<Association> parent; // I am parent
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "child")
    private Association child; // I am child

    public Spravochnik() {
        setParent(null);
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getKod() {
        return kod;
    }

    public void setKod(String newKod) {
        this.kod = newKod;
    }

    public String getName() {
        return name;
    }

    public void setName(String newName) {
        this.name = newName;
    }

    public boolean isFolder() {
        return folder;
    }

    public void setFolder(boolean folder) {
        this.folder = folder;
    }

    public boolean isAncestor(Spravochnik ancestor) {
        Spravochnik tryAncestor = getParent();
        while (tryAncestor != null) {
            if (ancestor.equals(tryAncestor)) {
                return true;
            }
            tryAncestor = tryAncestor.getParent();
        }
        return false;
    }

    public Spravochnik getParent() {
        return child != null ? child.getParent() : null;
    }

    public void setParent(Spravochnik newParent) {

        // Родителем может стать:


        if ((newParent == null) ||              // Нулевая папка
                (newParent.isFolder() &&         //Папка
                (!newParent.isAncestor(this)) && // не потомок
                (!newParent.equals(this)))) {        // не сам объект
            if (child == null) {
                child = new Association();
                child.setChild(this);
            }

            child.setParent(newParent);


        }

    }

    public void addChild(Spravochnik child) {


        // Ребенка можно добавить
        if ((!isAncestor(child)) && // Если он не предок
                (!equals(child))) {      // Не он сам
            Association association = new Association();
            association.setChild(child);
            association.setParent(this);
            child.setParent(this);

            if (parent == null) {
                parent = new HashSet<Association>();
            }
            parent.add(association);
        }


    }

    public void addChildren(Collection<Spravochnik> children) {
        Iterator iterator = children.iterator();
        while (iterator.hasNext()) {
            addChild((Spravochnik) iterator.next());
        }

    }

  

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Spravochnik)) {
            return false;
        }
        Spravochnik other = (Spravochnik) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entities.Spravochnik[id=" + id + "] Parent: "+child.getParent();
    }
}

 

Association.java

Код

package entities;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;


/**
 *
 * @author poul
 */
@Entity
@Table(name = "Assocition")
public class Association implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy=GenerationType.AUTO)    
    private Long id;
    
    @JoinColumn(name = "ID_PARENT", referencedColumnName = "ID")
    @ManyToOne
    private Spravochnik parent;
    
    @JoinColumn(name = "ID_CHILD", referencedColumnName = "ID")
    @OneToOne 
    private Spravochnik child;
    

    public Spravochnik getChild() {
        return child;
    }

    public void setChild(Spravochnik child) {
        this.child = (Spravochnik)child;
    }

    public Spravochnik getParent() {
        return parent;
    }

    public void setParent(Spravochnik parent) {
        this.parent = (Spravochnik)parent;
    }
  
            

    public void setId(Long id) {
        this.id = id;
    }


    public Long getId() {
        return id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Association)) {
            return false;
        }
        Association other = (Association) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entities.FolderAssociation[id=" + id + "]";
    }

}
 


PM MAIL   Вверх
powerOn
Дата 23.2.2008, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Может быть просто перенести всю функциональность класса Association в класс Spravochnik? Тогда класс Association вообще не будет нужен. Пусть класс Spravochnik сам рулит своими связями.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
poulmart
Дата 23.2.2008, 10:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



Тут дело не в том что что один класс или два.


А вот в чем:

Spravochnik                                             ExtendedSpravochnik

setParent(Spravochnik)                            setParent(ExtendedSpravochnik)                 
Spravochnik getparent()                          ExtendedSpravochnik getparent()
setChild(Spravochnik)                              setChild(ExtendedSpravochnik)
Spravochnik getChild()                             ExtendedSpravochnik getChild()

методы делаю одно и то же. Отличие только тип выдаваемых и принимаемых объектов.

Теперь по поводу 
Цитата

Может быть просто перенести всю функциональность класса Association в класс Spravochnik


Почему я таблицу разбил на две части.


Изначально я хотел сделать вот такую таблица:

Таблица

ID -
Name
ID_Parent (Таблица.ID)

В скобках указан внешний ключ.

Но база отказалась принимать внешний ключ из этой же таблицы.

Пришлось разбивать на две таблицы.

Таблица 1 (Справочник)

ID
Name

Таблица 2 (Ассоциации)

ID 
ID_PARENT (Таблица1.ID)
ID_CHILD (Таблица1.ID)

Ну а дальше принцип JPA

одна таблица - один объект.





















PM MAIL   Вверх
Kangaroo
Дата 23.2.2008, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


AA - Aussie Animal
****


Профиль
Группа: Участник Клуба
Сообщений: 2042
Регистрация: 7.10.2006
Где: US

Репутация: 14
Всего: 104



Цитата(poulmart @  23.2.2008,  09:16 Найти цитируемый пост)
методы делаю одно и то же. Отличие только тип выдаваемых и принимаемых объектов.

Зачем делать такие же методы для ExtendedSpravochnik ? Нужно просто использовать методы Spavochnik. В те методы параметром можно передать и Spravochnik i ExtendedSpravochnik.



Цитата(poulmart @  23.2.2008,  09:16 Найти цитируемый пост)
Но база отказалась принимать внешний ключ из этой же таблицы.

Странно. Должно работать. Это стандартное хранение иерархие в БД. Что за база?


--------------------
Lost....
PM MAIL MSN   Вверх
poulmart
Дата 23.2.2008, 17:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



Цитата


Цитата

Но база отказалась принимать внешний ключ из этой же таблицы.


Странно. Должно работать. Это стандартное хранение иерархие в БД. Что за база?


Понял. Спасибо. После более детального чтения документации все заработало.

БД - Derby

А вот код создания таблицы.

Код

create table "POUL".TEST_X2
(
    ID BIGINT not null primary key,
    NAME VARCHAR(100) not null UNique,
    ID_PARENT BIGINT, 
        FOREIGN KEY(ID_PARENT) REFERENCES "POUL".TEST_X2(ID) ON UPDATE RESTRICT ON DELETE RESTRICT
        
)


Теперь по поводу расширения функционала.

Имеется базовый класс Справочника. в нем реализована  общая для всех справочников логика. 
А на базе этого класса создавать конкретные справочники. Например Goods , Customers.
Просто хочется убрать возможность добавления Goods в Customers  и наоборот в принципе.








PM MAIL   Вверх
powerOn
Дата 24.2.2008, 12:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(poulmart @  23.2.2008,  17:53 Найти цитируемый пост)
Например Goods , Customers.
Просто хочется убрать возможность добавления Goods в Customers  и наоборот в принципе.


Напишите ваш класс с использованием Generic, тогда компилятор будет следить за типом справочника. Вот тут есть туториал.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
poulmart
Дата 27.2.2008, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



Все ОК. То что надо.

Спасибо powerOn,

Вот тестовый пример, если кому еще надо.




Код

public interface HelloInterface<Type> {
    public Type getParent();
    public void setParent(Type newParent);
}


Код

public class Hello<Hello> implements HelloInterface<Hello>{
    
    private Hello parent;

    public Hello getParent() {
        return parent;
    }

    public void setParent(Hello newParent) {
        this.parent = newParent;
    }
    

}


Код

public class ExtendsHello extends Hello<ExtendsHello> {

 

}






PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.1719 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.