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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Jpa inheritance & NamedQuery 
:(
    Опции темы
v2v
Дата 27.8.2010, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1620
Регистрация: 20.9.2006
Где: Киев

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



Код


@Entity
@NamedQueries( { @NamedQuery(name = "Computer.All", query = "SELECT OBJECT(c) FROM Computer c JOIN c.blocks") } )
class Computer {
@Id
Integer id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "computer", cascade = CascadeType.ALL)
private List<AbstractBlock> blocks = new ArrayList<AbstractBlock>();
}

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class AbstractBlock {
@Id
Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(insertable = false, updatable = false)
Computer computer;

}

@Entity
class Monitor extends AbstractBlock { }

@Entity
class Keyboard extends AbstractBlock { }

@Entity
class Mouse extends AbstractBlock { }


--

Имеем следующую задачу. Есть сущность "компьютер", которой соответсвует таблица "Computer" в базе данных.
Компьютер состоит из элементов(блоков) разных типов: монитор, клавиатура, мишь и т.д.
Каждому типу соответсвует своя таблица в бд Monitor, Keyboard, Mouse. Все компоненты компьютера наследуются от абстрактной сущности AbstractBlock.
В мапинге указан отношение 1 компьютер ко многим AbstractBlock, но понятно что в массиве blocks находятся не абстрактные сущности, а реальные компоненты мыши, клавиатуры ит.д.

Проблема в генерящимся NamedQuery для компьютера. Дело в том что он не понимает что хоть и мапимся мы на абстрактную сущность, реальная выборка должна происходить из сущностей-наследников.
В итоге получаем следующий неправильный запрос:
Код

select a.*,b.* from Computer c, AbstractBlock b where c.id = b.computer_id;

Таблички AbstractBlock не существует (см. стратегию наследования TABLE_PER_CLASS).
Хотелось бы что бы сгенерился запрос в виде:
Код

select a.*,b.* from Computer c, Monitor m, Keyboard k, Mouse m ...


Как можно этого добиться?


--------------------
PM   Вверх
firedrago
Дата 28.8.2010, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



http://en.wikibooks.org/wiki/Java_Persistence/Inheritance
Цитата

Common Problems
*Poor query performance

    The main disadvantage to the table per class model is queries or relationships to the root or branch classes become expensive. Querying the root or branch classes require multiple queries, or unions. One solution is to use single table inheritance instead, this is good if the classes have a lot in common, but if it is a big hierarchy and the subclasses have little in common this may not be desirable. Another solution is to remove the table per class inheritance and instead use a MappedSuperclass, but this means that you can no longer query or have relationships to the class.

*Issues with ordering and joins

    Because table per class inheritance requires multiple queries, or unions, you cannot join to, fetch join, or traverse them in queries. Also when ordering is used the results will be ordered by class, then by the ordering. These limitations depend on your JPA provider, some JPA provider may have other limitations, or not support table per class at all as it is optional in the JPA spec. 

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

@NamedQueries( { @NamedQuery(name = "Computer.All", query = "SELECT с FROM Computer c") } )

и никакого гимороя...

удачи!

Это сообщение отредактировал(а) firedrago - 28.8.2010, 15:58
PM MAIL   Вверх
v2v
Дата 29.8.2010, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1620
Регистрация: 20.9.2006
Где: Киев

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



при указанном запросе всё равно будет "лажа":
Цитата

Querying the root or branch classes require multiple queries, or unions.

после того как запрос вытащит сущность "компьютер", он начинает ходить по связанным таблицам и вытаскивать дополнительные сущности, при чём опять не обращая внимание на наследование:
Код

select b from AbstracBlock where b.computer=?



--------------------
PM   Вверх
firedrago
Дата 29.8.2010, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



 smile все там в порядке.... Так и должно быть, ты же сам поставил
Код

@OneToMany(fetch = FetchType.LAZY, mappedBy = "computer", cascade = CascadeType.ALL)

При Lazy твои блокс будут вытаскиваться толко когда ты к ним обратишся... Поставь Eager и они будут вытаскиваться сразу.
PM MAIL   Вверх
v2v
Дата 29.8.2010, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1620
Регистрация: 20.9.2006
Где: Киев

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



firedrago, ты не понял. То что оно потом вытаскивает - это Ок. Проблема в том, что оно вытаскивает из не существующей таблицы AbstracBlock, когда должно обращаться к дочерним сущностям.  smile 



--------------------
PM   Вверх
firedrago
Дата 29.8.2010, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



 smile  так, еще раз ... ты хочеш использовать исключительно TABLE_PER_CLASS и что бы небыло AbstractBlock ?!
я не уверен, что без AbstractBlock table оно у тебя будет работать..... даже теоретически не представляю как он должен следить за PK....
например в случае с JOINED всегда есть таблица из Abstract класса..... в ней есть PK(id) и DTYPE(тип твоих классов унаследовавшие Abstract)....
таблица наследника FK(id) и все, что ты в объекте еще засунул....
вобщем мое мнение, что без таблицы Abstract ничего не выйдет.....

PM MAIL   Вверх
firedrago
Дата 29.8.2010, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



так .... только что попробывал - все работает, но без таблицы AbstractBlocks не обойтись...
использовал EclipseLink
итак классы :
Код

package test.eclipselink.data;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.GeneratedValue;

@Entity
@NamedQueries({ @NamedQuery(name = "Computer.All", query = "SELECT c FROM Computer c") })
public class Computer {
    @Id
    @GeneratedValue
    Integer id;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "computer", cascade = CascadeType.ALL)
    private List<AbstractBlock> blocks = new ArrayList<AbstractBlock>();
    
    public List<AbstractBlock> getBlocks() {
        return blocks;
    }
    public void setBlocks(List<AbstractBlock> blocks) {
        this.blocks = blocks;
    }
    
    public void addBlock(AbstractBlock block){
        block.setComputer(this);
        getBlocks().add(block);
    }
}


!!!!!! Entity "AbstractBlock" uses table-per-concrete-class inheritance which is not portable and may not be supported by the JPA provider
Код

package test.eclipselink.data;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import static javax.persistence.InheritanceType.TABLE_PER_CLASS;

@Entity
@Inheritance(strategy = TABLE_PER_CLASS) // Entity "AbstractBlock" uses table-per-concrete-class inheritance which is not portable and may not be supported by the JPA provider    
public abstract class AbstractBlock {
    @Id
    @GeneratedValue
    Integer id;
    
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
    
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(insertable = false, updatable = false)
    Computer computer;

    public Computer getComputer() {
        return computer;
    }

    public void setComputer(Computer computer) {
        this.computer = computer;
    }
}


Код

package test.eclipselink.data;

import javax.persistence.Entity;

@Entity
public class Keyboard extends AbstractBlock {

}


Код

package test.eclipselink.data;

import javax.persistence.Entity;

@Entity
public class Monitor extends AbstractBlock {

}


создаем записываем и читаем через query...
Код

        Computer c1 = new Computer();
        c1.addBlock(new Monitor());
    
        Computer c2 = new Computer();
        c2.addBlock(new Keyboard());

        Computer c3 = new Computer();
        c3.addBlock(new Monitor());
        c3.addBlock(new Keyboard());

        
        
        EntityManager em = getEntityManager();

        em.getTransaction().begin();
        em.persist(c1);
        em.persist(c2);
        em.persist(c3);
        em.getTransaction().commit();
        
        // давай ка все компы!!!
        em.getTransaction().begin();
        Query query = em.createNamedQuery("Computer.All");
        @SuppressWarnings("unchecked")
        List<Computer> list = query.getResultList();
        em.getTransaction().commit();
        for(Computer comp : list){
            System.out.println("Found Computer with id:" + comp.getId());
            if(comp.getBlocks().size() > 0){
                for(AbstractBlock block : comp.getBlocks()){
                    if(block instanceof Monitor){
                        System.out.println("Monitor found");
                    }else if(block instanceof Keyboard){
                        System.out.println("Keyboard found");
                    }
                }
            }
        }


смотрим консоль...
Код

[EL Config]: The access type for the persistent class [class test.eclipselink.data.AbstractBlock] is set to [FIELD].
[EL Config]: The target entity (reference) class for the many to one mapping element [field computer] is being defaulted to: class test.eclipselink.data.Computer.
[EL Config]: The access type for the persistent class [class test.eclipselink.data.Keyboard] is set to [FIELD].
[EL Config]: The access type for the persistent class [class test.eclipselink.data.Monitor] is set to [FIELD].
[EL Config]: The access type for the persistent class [class test.eclipselink.data.Computer] is set to [FIELD].
[EL Config]: The target entity (reference) class for the one to many mapping element [field blocks] is being defaulted to: class test.eclipselink.data.AbstractBlock.
[EL Config]: The alias name for the entity class [class test.eclipselink.data.Keyboard] is being defaulted to: Keyboard.
[EL Config]: The alias name for the entity class [class test.eclipselink.data.AbstractBlock] is being defaulted to: AbstractBlock.
[EL Config]: The table name for entity [class test.eclipselink.data.AbstractBlock] is being defaulted to: ABSTRACTBLOCK.
[EL Config]: The column name for element [field id] is being defaulted to: ID.
[EL Config]: The table name for entity [class test.eclipselink.data.Keyboard] is being defaulted to: KEYBOARD.
[EL Config]: The target entity (reference) class for the many to one mapping element [field computer] is being defaulted to: class test.eclipselink.data.Computer.
[EL Config]: The column name for element [field id] is being defaulted to: ID.
[EL Config]: The alias name for the entity class [class test.eclipselink.data.Monitor] is being defaulted to: Monitor.
[EL Config]: The table name for entity [class test.eclipselink.data.Monitor] is being defaulted to: MONITOR.
[EL Config]: The target entity (reference) class for the many to one mapping element [field computer] is being defaulted to: class test.eclipselink.data.Computer.
[EL Config]: The column name for element [field id] is being defaulted to: ID.
[EL Config]: The alias name for the entity class [class test.eclipselink.data.Computer] is being defaulted to: Computer.
[EL Config]: The table name for entity [class test.eclipselink.data.Computer] is being defaulted to: COMPUTER.
[EL Config]: The column name for element [field id] is being defaulted to: ID.
[EL Config]: The primary key column name for the mapping element [field computer] is being defaulted to: ID.
[EL Config]: The foreign key column name for the mapping element [field computer] is being defaulted to: COMPUTER_ID.
[EL Config]: The primary key column name for the mapping element [field computer] is being defaulted to: ID.
[EL Config]: The foreign key column name for the mapping element [field computer] is being defaulted to: COMPUTER_ID.
[EL Config]: The primary key column name for the mapping element [field computer] is being defaulted to: ID.
[EL Config]: The foreign key column name for the mapping element [field computer] is being defaulted to: COMPUTER_ID.
[EL Info]: EclipseLink, version: Eclipse Persistence Services - 2.1.0.v20100614-r7608
[EL Fine]: Detected Vendor platform: org.eclipse.persistence.platform.database.MySQLPlatform
[EL Config]: Connection(1208347121)--connecting(DatabaseLogin(
    platform=>MySQLPlatform
    user name=> "test"
    datasource URL=> "jdbc:mysql://127.0.0.1/test"
))
[EL Config]: Connection(1205434602)--Connected: jdbc:mysql://127.0.0.1/test
    User: test@localhost
    Database: MySQL  Version: 5.1.43-log
    Driver: MySQL-AB JDBC Driver  Version: mysql-connector-java-5.1.10 ( Revision: ${svn.Revision} )
[EL Info]: test.eclipselink.data_transactionType=RESOURCE_LOCAL_url=jdbc:mysql://127.0.0.1/test_user=test login successful
[EL Config]: The default table generator could not locate or convert a java type (null) into a database type for database field (KEYBOARD.COMPUTER_ID). The generator uses java.lang.String as default java type for the field.
[EL Config]: The default table generator could not locate or convert a java type (null) into a database type for database field (MONITOR.COMPUTER_ID). The generator uses java.lang.String as default java type for the field.
[EL Config]: The default table generator could not locate or convert a java type (null) into a database type for database field (ABSTRACTBLOCK.COMPUTER_ID). The generator uses java.lang.String as default java type for the field.
[EL Fine]: Connection(1205434602)--CREATE TABLE MONITOR (ID INTEGER NOT NULL, COMPUTER_ID INTEGER, PRIMARY KEY (ID))
[EL Fine]: Connection(1205434602)--CREATE TABLE ABSTRACTBLOCK (COMPUTER_ID INTEGER)
[EL Fine]: Connection(1205434602)--CREATE TABLE COMPUTER (ID INTEGER NOT NULL, PRIMARY KEY (ID))
[EL Fine]: Connection(1205434602)--CREATE TABLE KEYBOARD (ID INTEGER NOT NULL, COMPUTER_ID INTEGER, PRIMARY KEY (ID))
[EL Fine]: Connection(1205434602)--ALTER TABLE MONITOR ADD CONSTRAINT FK_MONITOR_COMPUTER_ID FOREIGN KEY (COMPUTER_ID) REFERENCES COMPUTER (ID)
[EL Fine]: Connection(1205434602)--ALTER TABLE ABSTRACTBLOCK ADD CONSTRAINT FK_ABSTRACTBLOCK_COMPUTER_ID FOREIGN KEY (COMPUTER_ID) REFERENCES COMPUTER (ID)
[EL Fine]: Connection(1205434602)--ALTER TABLE KEYBOARD ADD CONSTRAINT FK_KEYBOARD_COMPUTER_ID FOREIGN KEY (COMPUTER_ID) REFERENCES COMPUTER (ID)
[EL Fine]: Connection(1205434602)--INSERT INTO COMPUTER (ID) VALUES (?)
    bind => [203]
[EL Fine]: Connection(1205434602)--INSERT INTO COMPUTER (ID) VALUES (?)
    bind => [205]
[EL Fine]: Connection(1205434602)--INSERT INTO COMPUTER (ID) VALUES (?)
    bind => [201]
[EL Fine]: Connection(1205434602)--INSERT INTO KEYBOARD (ID) VALUES (?)
    bind => [204]
[EL Fine]: Connection(1205434602)--INSERT INTO KEYBOARD (ID) VALUES (?)
    bind => [207]
[EL Fine]: Connection(1205434602)--INSERT INTO MONITOR (ID) VALUES (?)
    bind => [202]
[EL Fine]: Connection(1205434602)--INSERT INTO MONITOR (ID) VALUES (?)
    bind => [206]


[EL Fine]: Connection(1205434602)--SELECT ID FROM COMPUTER
Found Computer with id:201
Monitor found
Found Computer with id:203
Keyboard found
Found Computer with id:205
Monitor found
Keyboard found

CREATE TABLE ABSTRACTBLOCK (COMPUTER_ID INTEGER) - автоматом.....
как видно, все блоки нашел....
PM MAIL   Вверх
firedrago
Дата 29.8.2010, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



к стати еще одна злая ошибка 
поменяй 
Код

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(insertable = false, updatable = false)
    Computer computer;

на
Код

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(updatable = false)
    Computer computer;

иначе он не будет записывать ID в базу

и все-таки лучше использовать JOINED..... 

удачи!

Это сообщение отредактировал(а) firedrago - 29.8.2010, 20:00
PM MAIL   Вверх
v2v
Дата 30.8.2010, 08:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1620
Регистрация: 20.9.2006
Где: Киев

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



странно как то ... TABLE_PER_CLASS наследование, как то слишком в таком случае на JOINED смахивает.
Но всё равно спасибо за помощь, посмотрю что можно сделать.


--------------------
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "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.0500 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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