powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / @OneToMany
25 сообщений из 26, страница 1 из 2
@OneToMany
    #34212458
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго всем времени суток.

Есть EJB3.
Есть отношение @OneToMany
Таблица А - одна запись
Таблица B - много.

Связь должна двунаправленная.

В энтити для таблицы А пишу
@OneToMany(mappedBy="field из ентити для В")
private List<Permission> permissions = new ArrayList<Permission>();

В энтити для таблицы B пишу
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="id_application")
private Application application;

Ведущей в этом отношении выстыпает таблица В.
При удалении записи из А выполняется N+1 запрос для чистки B.\

Как мне сделать чтобы ведущей в отношении стала А ?
и при удалении из А выполняля delete from B по ключу связи ?
...
Рейтинг: 0 / 0
@OneToMany
    #34212490
mozheyko_d
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Поставить каскад в @OneToMany
...
Рейтинг: 0 / 0
@OneToMany
    #34212522
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В энтити для таблицы А добавил

@OneToMany(mappedBy="field из ентити для В", cascade=CascadeType.ALL)
private List<Permission> permissions = new ArrayList<Permission>();

Результат тот же!. тут удея в том что в отношении главной таблица B.
КАк сделать чтобы в отношении главной стала А ?

это сделать просто, если отношение однонаправленное, в двунаправленном - не знаю как!.
...
Рейтинг: 0 / 0
@OneToMany
    #34212574
pretender
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
"In a bidirectional relationship, one of the sides (and only one) has to be
the owner: the owner is responsible for the association column(s) update.
To declare a side as not responsible for the relationship, the attribute mappedBy is used"

Все дело в mappedBy
...
Рейтинг: 0 / 0
@OneToMany
    #34213213
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нароод !!!!!!

че то я ваще зашиваюсь!!!!!! :((
попробуя сначала!!!!! но немного подругому!.

Есть отношение @OneToMany
Таблица А - одна запись
Таблица B - много.

Связь должна ОДНОНАПРАВЛЕННАЯ

В энтити для таблицы А пишу
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="id_application", nullable=false, insertable=true)
private List<Permission> permissions = new ArrayList<Permission>();

В энтити для таблицы B без ссылок и упоминаний на А.

перед удалением ентити по А проихходит вычитавание всех идентификаторов для В по внешнему ключу а потом само удаление проиходит по идентификаторам из В. т.е. три записи связано - три оператора delete. и т.д.
как бы ему намекнуть что удалять можна по внешнему ключу одним delete:) ???????
...
Рейтинг: 0 / 0
@OneToMany
    #34213231
mozheyko_d
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
это тебе к разработчикам контейнера
...
Рейтинг: 0 / 0
@OneToMany
    #34213413
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OneToMany
...
Связь должна ОДНОНАПРАВЛЕННАЯ
...
перед удалением ентити по А проихходит вычитавание всех идентификаторов для В по внешнему ключу а потом само удаление проиходит по идентификаторам из В. т.е. три записи связано - три оператора delete. и т.д.
как бы ему намекнуть что удалять можна по внешнему ключу одним delete:) ???????

Если у вас hibernate то вот ответ на ваш вопрос http://www.sql.ru/forum/actualthread.aspx?tid=280115#2534263
...
Рейтинг: 0 / 0
@OneToMany
    #34213730
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
прочитал инфу по линку.
проникся важностью момента :) даа действительно надобы внимательнее раляционную модель с маппингом вязать!!.

но всё это хорошо! но в EJB3 нет анатации all-delete-orhan! есть только хорошо изветсные CascadeType.ALL и д.р.

использовать чисто гибернетовские анатации не хотелось бы!!!. хотелось бы на чистом EJB3.
так возможно ?
...
Рейтинг: 0 / 0
@OneToMany
    #34213859
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OneToManyпрочитал инфу по линку.
использовать чисто гибернетовские анатации не хотелось бы!!!. хотелось бы на чистом EJB3.
так возможно ?

Можно - сделайте связь bidirectional
...
Рейтинг: 0 / 0
@OneToMany
    #34213941
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
так она у меня и так бидиректионал.

В энтити для таблицы А (там де одна запись) пишу

@OneToMany(mappedBy="application", cascade=CascadeType.ALL)
private List<Permission> permissions = new ArrayList<Permission>();

В энтити для таблицы B (много записей) пишу
@ManyToOne
@JoinColumn(name="id_application")
private Application application;

Удаляю так :
Application a = manager.find(Application.class, application.getId());
manager.remove(a);

в итоге последовательно удаляются записи из B по своим айдишникам. три записи - три делете!. черыте - четыре делете.

funikovyuri - что вы имеете ввиду ? или я неправильно мапиг оформил ?
...
Рейтинг: 0 / 0
@OneToMany
    #34213952
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
можно и так :
Application a = manager.find(Application.class, application.getId());

manager.createQuery("delete from Permission where application=:application").setParameter("application", a).executeUpdate();

manager.remove(a);

но хотелось бы обойтись каскадностью для чистоты эксперимента.
...
Рейтинг: 0 / 0
@OneToMany
    #34214195
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опция Cascade.ALL нужен для того чтобы эскалировать операции save/update/delete на объекты, дочерние по отношение к данному объекту. К проблеме лишних delete from .. она отношения не имеет. Как написано по ссылке - в РБД нету связи один-ко-многим, поэтому hibernate так себя ведет. В случае если хибернейт будет иметь связь многие-к-одному он будет посылать такой delete какой вам, судя по всему, нужен.

Судя по коду который вы в последних сообщениях привели у вас все верно написано, только @ManyToOne аннотация должна быть у getter'а, а не у самого property (@OneToMany при этом не трогайте)
...
Рейтинг: 0 / 0
@OneToMany
    #34215014
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
да какая разница, как я анатирую - проперть или геттер ? это вопрос вкуса и привычки.
насколько я понял из спецификации ejb3 смотрит как анатирован айдишник - если он анатирован пропертью - всё остальное тоже должно быть пропертью, если через гетер - всё остальное - также.

но всё же последовал вашему совету и перенес @ManyToOne в гетер - поведение не изменилось - всё также гонит кучу делете.
...
Рейтинг: 0 / 0
@OneToMany
    #34215077
expp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
про четыре delete: я признаюзь ни разу не видел у хибера таких delete. Эти четыре запроса ваполняются в одном batch'e поэтому проблем никаких. Думаю этим можно не грузиться. Такое поведение обьясняется следующим: delete каскадится с masterа на detailы они помечаются в сессии как коцнутые. При flush'е сессии хибер в нужном порядке удаляет объекты по их PK. И если например вы удалили пару мастеров (и кучу детэйлов с ними), то при flushЕ он не будет собирать detailы в пачки для удаления по одному FK. СУБДу думаю тоже фиолетово.
...
Рейтинг: 0 / 0
@OneToMany
    #34215225
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
да какая разница, как я анатирую - проперть или геттер ? это вопрос вкуса и привычки.
насколько я понял из спецификации ejb3 смотрит как анатирован айдишник - если он анатирован пропертью - всё остальное тоже должно быть пропертью, если через гетер - всё остальное - также.

но всё же последовал вашему совету и перенес @ManyToOne в гетер - поведение не изменилось - всё также гонит кучу делете.
...
Рейтинг: 0 / 0
@OneToMany
    #34215240
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
админ - прошу прощения за то что гоню посятнно дубликаты постов. запарился вкрай.
...
Рейтинг: 0 / 0
@OneToMany
    #34215309
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
попробовал удалить сразу в батче два мастера -
да действительно он спева подчищает за первым мастером потом его грохает
потом подчищает за вторым и грохает его.

в итоге - было 2 мастера у каждого по две дочерних записи.
всего запросов :
1 оператор делете на каждый чаил (4 штуки всего) + 2 delete на мастерах. = 6 операторов.

то,что он делает это в батче - это не повод успокаиваться. как я понял - батч это одно обращение к базе. т.е. по сути имеем аналог на pl/sql

begin
delete from child where id = ..
delete from child where id = ..
delete from master where id = ..

delete from child where id = ..
delete from child where id = ..
delete from master where id = ..
end;

а если там тысяча или милион ? уууууужжж наверняка логических чтений будет намного больше еслибы удаление шло по fk.

я правильно представляю происходящую картину ?
...
Рейтинг: 0 / 0
@OneToMany
    #34215326
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OneToMany
я правильно представляю происходящую картину ?

нет... удалять одним delete'ом записи по FK для одного родителя hibernate может... сейчас немного освобожусь - нарисую вам пример
...
Рейтинг: 0 / 0
@OneToMany
    #34215435
expp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OneToMany т.е. по сути имеем аналог на pl/sql
Сранение с PL/SQL, думаю не совсем имеет смысл, т.к. он выполняется базой, а тут проблема в том что хибер работает в другом адр. пр-ве. и общаются они последовательными запросами. begin/end - это транзакция - думаю за рамками сабжа. Если бы батча не было: запрос№1 "коц первую", ждём подтверждения, следующий запрос, ждём .... Батч уходит одним запросом. Т.е.не надо ждать выполнения мелких запросов. а субду думаю пофиг. можете опровергнуть бенчмарком. тока коректным плиз!!!
...
Рейтинг: 0 / 0
@OneToMany
    #34216135
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
to expp -> по-моему вы выразили тоже самое мнение что и я. только другими словами.

я утверждаю что в случае батча хибер собирает кучу операторов в кучу и отправляет их целым блоком за одно обращение к базе!. выйгрыш по скорости конечно есть по сравнению с обращением к базе за кажым делет, но это не ПРИНЦИПИАЛЬНО!.

юзеру все равно придется ждать завершения батча!. экономим время тока за счет сокращения лишних обращений. Объем производимой работы тот же!.

что именно вы хотите чтобы я опроверг? уточните плз.
...
Рейтинг: 0 / 0
@OneToMany
    #34216232
expp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну покажите на тесте что стирать по FK быстрее чем по PK. Думаю разница незначительная. А разница между batch/неbatch принципиальная поскольку существенна.
...
Рейтинг: 0 / 0
@OneToMany
    #34216737
OneToMany
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
извольте
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
drop table b;
/
drop table a;
/
create table a(pk int primary key, f1 int)
/
create table b(pk int primary key, a_f1 int, b_f1 varchar2( 1000 ))
/
ALTER TABLE b ADD CONSTRAINT fk FOREIGN KEY (a_f1) REFERENCES a(pk)
/
create index ind_b on b(a_f1)
/

declare x int; 
begin
    x := dbms_utility.get_time;
    for i in  1  ..  10  loop
     insert into a(pk, f1) values(i, i);
     for j in  1  ..  10000  loop
       insert into b(pk, a_f1, b_f1) values(i* 100000  + j, i, 'xxxxxxxxxxxxxxxx');         
     end loop;     
    end loop;    
    dbms_output.put_line('Вставляли : ' || (dbms_utility.get_time - x));
    commit;
    
    x := dbms_utility.get_time;
    for i in  1  ..  10  loop
     
     for j in  1  ..  10000  loop
      delete from b where pk = i* 100000  + j;
     end loop;       
     
     delete from a where pk = i;
    end loop;
    dbms_output.put_line(Построчно : ' || (dbms_utility.get_time - x));    
    commit;
    
    for i in 1 .. 10 loop
     insert into a(pk, f1) values(i, i);
     for j in 1 .. 10000 loop
          insert into b(pk, a_f1, b_f1) values(i*100000 + j, i, 'xxxxxxxxxxxxxxxx');         
     end loop;     
    end loop;    
    commit;
    
    x := dbms_utility.get_time;    
    for i in 1 .. 10 loop
     delete from b where a_f1 = i;  
     delete from a where pk = i;
    end loop;
    dbms_output.put_line(Зараз : ' || (dbms_utility.get_time - x));    
end;

результат

Вставляли : 4259
Построчно : 4587
Зараз : 3443


В итоге то что можно сделать одним оператором всегда быстрее чем несколькими.
об этом еще Том Кайт писал в своём двухтомнике!
естественно это всё применительно к ораклу.
...
Рейтинг: 0 / 0
@OneToMany
    #34217072
expp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я просил корректный тест.
хотелось бы убедиться что эти результаты воспроизводятся. запустите это плиз 10 раз (в одинаковых условиях, как это сделать я не знаю!!!). потом в скрипте пом5еняйте два способа удаления местами. и опять 10 раз в тех же условиях, плиз. вот потом можно посмотреть на результаты и как то их интерпритировать (см. мат стат)

дальше:

если же разница между двумя этими способами составлят 1,5 раза, при кол-ве итераций на 4 порядка больше то я думаю это незначительный оверхэд (если это вобще не тормоза интерпритатора PLа на for'е).

ещё дальше:

если эти полтора раза для на 4ёх порядках для вас существенны, то может вам не нужен хибер? он не для mass updateов

в конце:

остаётся ждать пока Юрий не освободиться
...
Рейтинг: 0 / 0
@OneToMany
    #34217133
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Странное дело - я был уверен что уже решал эту задачу... но сейчас это сделать не удалось... т.е. да bidirectional убирает лишние update'ы, но не лишние delete'ы. Так что пока увы :(


Зато у меня есть 2 workaround'а

1й это удалять объекты таким кодом:
Код: plaintext
1.
2.
3.
4.
5.
session.createQuery("delete EntityB where entityA_id=?").setInteger( 0 , entityA.getId()).executeUpdate();
entityA.setEntitiesB( null );
		
session.delete(entityA);


если убрать этот код в DAO метод то на мой взгляд получается нормально

2й это использовать Hibernate annotations extension, а именно @OnDelete(action=OnDeleteAction.CASCADE) совместно с каскадным DRI в схеме БД
...
Рейтинг: 0 / 0
@OneToMany
    #34217811
expp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну короче
1. неподходит. т.к. требует flush'а сессии.
2. ниасилил.
в общем я предлагаю, собраться вместе и забить - это фигня а не оверхэд
...
Рейтинг: 0 / 0
25 сообщений из 26, страница 1 из 2
Форумы / Java [игнор отключен] [закрыт для гостей] / @OneToMany
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]