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

Посоветуйте пожалуйста: есть сущность hibernate. Есть GUI JavaFX, меняющие ее поля. Все это внутри Spring.
Как оптимальным образом отловить факт того, что сущность "изменилась"? Мне не нужно знать что именно и каким образом - просто то что она в принципе была изменена. Сам hibernate такие сущности, если я верно понимаю, считает dirty, но какого-то "элементарного" (а-ля isDirty()) метода я не увидел.

Видятся примерно такие пути:
1. Ставить флаг (либо в сущности на сеттерах либо в ГУИ на полях при изменении). Решение рабочее НО мне не нравится что если поставить "новое" значение а потом обратно "старое" флаг останется в положении "сущность была изменена".
2. Делать копию сущности и сравнивать все поля - не нравится потому что это ресурсы и время.
3. Делать "наблюдатель", но для такой "фигни" мне кажется это как из рушки по воробьям...
4. AOP тут не срабатывает (попробовал), потому что хибер делает прокси видимо.

Словом мой "победитель" все же наверное флаг, но может есть что более оптимальное о чем я и не подозреваю?

Спасибо.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303022
rdm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGab, hashCode
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303024
natanabrahamjr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а может аспект вешать не на саму сущность? :)
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303025
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdmRuslanGab, hashCode
Да попробую. Спасибо. По идее то что мне нужно. Жалко только придется до понедельника ждать

natanabrahamjrа может аспект вешать не на саму сущность? :)
А на кого? Если на GUI так там нет "универсального сеттера" поля меняются и "вбиванием" текста и, к примеру, выбором чего-то в чекбоксе, и через DatePicker. На сущность было бы эдементарно - все что внутри такого-то пакета и все методы начинающиеся с SET. Увы так не прокатило:(
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303052
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabЕсли на GUI так там нет "универсального сеттера"
Он причём?
MVVM паттерн у JavaFX, вот в последнем слое перед ГУИ и делайте.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303326
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123,

Нет я от MVVP отказался если честно - перед этим проект был где все было именно с MVVM и все ок, а тут просто "двухслойное" небольшое приложение без сервера и не захотел я это городить. Таки вот поимев опыт MVVM считаю все же что для таких "небольших" проектов оно того не стоит, хотя может я не прав конечно... Тут всего 8 или 9 полей заполняются включая боксы и datepickerы, так что меняю поля сущности просто посредством слушателей этой формы. С MVVM этот момент конечно в лет бы решился, но тут пожалуй и хэша хватит - при отображении сущности всего-то достаточно в локальную переменную сохранить ее копию а дальше когда надо сравнить хэш имеющейся сущности с этой самой копией и всех делов - очень мне понравилось решение. Как всегда на поверхности все лежит не надо мудрить...
Но спасибо!
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303354
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGab,
Может и оверхед в вашем проекте.
Про хэш этот метод точно работает?
Код покажите тогда, раз вопрос решён.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303370
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabКак оптимальным образом отловить факт того, что сущность "изменилась"? DefaultSaveOrUpdateEventListener

либо

заюзать Service/DAO/Repository и fire'ить вручную
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303385
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123,

Попробую завтра нормально ли будет с хэшем. А отчего хэшу не работать? Переопределю его во всех энтитях (если уже это не сделано - не помню), коих не много, чтобы и с "дочерними" нормально проходило и по идее все. Ну я надеюсь по крайней мере. Код покажу проблемы нет. Завтра будет возможность только.

Usman,

Насчет DefaultSaveOrUpdateEventListener насколько я понимаю "listener used by Hibernate for handling save-update events" означает, что он сработает перед апдэйтом/сэйвом. Это не совсем то что я ищу. Мне-то просто нужно в требуемый мне момент знать изменен/нет и все.
"заюзать ... и fire'ить вручную" - это собственно то что я имел ввиду под "флагом" - ставить его на "да" при изменении полей. Да так будет работать я просто и хотел знать может есть что проще уже готовое. К тому же идей со "флагом" имеет небольшой баг если поменять поле и позже поменять "обратно" - флаг останется в true хотя по сути ничего не менялось. Вот хэш ранее "посоветованный" мне кажется тем что надо как раз в моем случае.

Всем спасибо еще раз!
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303411
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabА отчего хэшу не работать? Переопределю его во всех энтитях
просто странный ты.
Вместо того чтобы в каждой сущности сделать флаг об изменении, т.е. одно доп.поле.
Ты будешь переписывать во всех сущностях проверку всех полей.
Пока, по ТЗ получается что оверхед у тебя.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303415
fsharp_fsharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabДобрый вечер!

Посоветуйте пожалуйста: есть сущность hibernate. Есть GUI JavaFX, меняющие ее поля. Все это внутри Spring.
Как оптимальным образом отловить факт того, что сущность "изменилась"? Мне не нужно знать что именно и каким образом - просто то что она в принципе была изменена. Сам hibernate такие сущности, если я верно понимаю, считает dirty, но какого-то "элементарного" (а-ля isDirty()) метода я не увидел.

Видятся примерно такие пути:
1. Ставить флаг (либо в сущности на сеттерах либо в ГУИ на полях при изменении). Решение рабочее НО мне не нравится что если поставить "новое" значение а потом обратно "старое" флаг останется в положении "сущность была изменена".
2. Делать копию сущности и сравнивать все поля - не нравится потому что это ресурсы и время.
3. Делать "наблюдатель", но для такой "фигни" мне кажется это как из рушки по воробьям...
4. AOP тут не срабатывает (попробовал), потому что хибер делает прокси видимо.

Словом мой "победитель" все же наверное флаг, но может есть что более оптимальное о чем я и не подозреваю?

Спасибо.

не спец в Java. но врядли это нормальный подход: "есть сущность hibernate. Есть GUI JavaFX, меняющие ее поля". на ГУИ должны быть другие типы, у которых есть возможность 2-направленного биндинга к контролам
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303416
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabК тому же идей со "флагом" имеет небольшой баг если поменять поле и позже поменять "обратно" - флаг останется в true хотя по сути ничего не менялось. Вот хэш ранее "посоветованный" мне кажется тем что надо как раз в моем случае.
ну, во-первых, это нормально когда в ворд я добавил символ, потом стёр, а звёздочка изменения документа так и осталась.
Хотя что мы говорим. Для чего сабж ты так и не сказал.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303501
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123Для чего сабж ты так и не сказал.
Да я не думал что это сильно важно До смешного просто все: если выбирается сущность (из таблицы tableview) снизу "выезжает" панель с полями для ее редактирования. Там же ок (что очевидно) и cancel. Весь сыр бор чтобы по нажатию на cancel а также на любую из прочих доступных опций в главном меню (оно сверху ну опять же не важно) глянуть была ли сущность изменена и если да сказать мол "Момент, ты же тут че-то менял. Точно хочешь уйти не сохранив?". Вот и усе...

fsharp_fsharpна ГУИ должны быть другие типы, у которых есть возможность 2-направленного биндинга к контролам
Я понимаю о чем вы говорили у меня на прошлом проекте так былою BindBidirectional прекрасно работает если вы делаете модель с XYZproperties, т.е. используете MVVM, от чего я отказался, ибо тут всего несколько полей редактируется решил что "слушателей" на них повесить проще. Есть конечно также вариант в модели и простые свойства и всякий StringProperty и прочие "замешать", но там проблемы с сереализацией да и вообще не очень мне такое решение. Словом у меня совсем обычная модель и простые листнеры, которые поля сущности меняют через сеттеры.

Petro123Вместо того чтобы в каждой сущности сделать флаг об изменении, т.е. одно доп.поле. Ты будешь переписывать во всех сущностях проверку всех полей.
Не совсем согласен. Флаг да одно поле, но его еще надо в каждый сеттер:) Конечно сложного ничего (тем более там сущностей всего ничего) и собственно это и был мой выбор если тут лучшего не посоветуют, но хэш как по мне так все же проще. Что там такого проблемного в "проверке всех полей"? Овверрайд метод ХэшКод и IDE сама сгенерит код строк на 7-10. И сделать это скажем раз 5. Искренне не вижу трудностей или проблем. Есть конечно теоретичские сомнения что при изменении дочерней сущности что-то будет "не так", но вообще говоря по идее все должно быть ок. А впоследствии этот подход еще и решит проблему сущности, которую изменили и изменили "назад" - если поменять "назад" хэш станет прежним. По идее.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303510
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabФлаг да одно поле, но его еще надо в каждый сеттер:)
ешкин кот.
- Далай один флаг на сессию а не на сущность. Зачем знать что именно изменилось?
- Ты предлагаешь перед выводом копировать сущности? Это же тоже код? Потом добавим код проверки по хешу или equals. Потом учтём что ID не должен проверятся на равность объектов. Потом учтём что сессии короткие и ты копию сущности должен вывести из сессии хибера.
- Как будем сравнивать сложный объект один ко многим - Персона с дочками-детьми.
...
И это всё вместо одной галки SetModify и GetModify boolean?
...
С точки зрения архитектуры, hashCode equals более системные вещи. А то что вы ищите - бизнес логика.
Я бы не мешал одно с другим. Но это IMHO.
Удачи!
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303515
rdm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class MyEntity {
 private int storeHashCode;

public void reset() {
   storeHashCode = hashCode();
}

public boolean isDirty() {
    return storeHashCode != hashCode();
}
}
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303517
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303626
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdm
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class MyEntity {
 private int storeHashCode;

public void reset() {
   storeHashCode = hashCode();
}

public boolean isDirty() {
    return storeHashCode != hashCode();
}
}



В вашем примере ресет надо будет вызывать из каждого сеттера? Тогда ведь это тот же "флаг" по сути, правда лишенный того что он будет выставлен при том что ищменения будут "возвращены". Вообще мне очень нравится решение. Если исходить из поста ниже что "@override hashCode" зло, то это решение вообще идеальное.

Usman , интересная статья, но я так и не понял чем конкретно это плохо если честно. Тем что после сохранения сущности в базе код станет другой? Так меня только часть "до сохранения" интересует... Не знаю словом. Я видел переопределение этих методов в проекте, которым руководил "опытный дядька" не то что я - все работало. Наверное и недостатки есть но для меня это пока не совсем очевидно...

Ну что, по моему мнению и проверке "на скорую руку" хэш таки показал себя молодцом. Изменения полей в сущности и в дочерних сущностях отрабатывают как надо - в том числе сущность получает первоначальный хэш если эти изменения "откатить". Обещанный код привожу, но полотно на 2 км думаю будет перебор - тут для примера сущность с одной дочерней (не смотрите на обилие полей - редактируемы из них только половина) а также контроллер (частично) AnchorPane, в которой собственно представлены ГУИ для редактирования. Пока логики проверки по сути нет - только вывод в консоль при нажатии "cancel". Однако подбное сравнение будет позже и в "родительском" контроллере (он передает в этот контрллер объект в метод "setAnfrageItem").

Мне решение с хэшем применительно к моей задаче понравилось, но я парень неопытный если это чем-то совсем плохо с удовольствием пересмотрю.

И еще раз всем спасибо!

"Основная" сущность:

Код: java
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.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
@Entity
@Table(name="Anfrage", schema="dbo", catalog="ReqManager")

public class Anfrage implements java.io.Serializable {


    private int anfrageId;     
    private Beleg beleg;
    private Karte karte;
    private Mandant mandant;
    private Provider provider;
    private Terminals terminals;
    private String anfrageNr;
    private Date anfrageDatum;
    private Date einkaufsDatum;
    private BigDecimal betrag;
    private Date fristablauf;
    private Date insertDate;
    @SuppressWarnings("unchecked")
    private Set<Email> emails = new HashSet(0);
    @SuppressWarnings("unchecked")
    private Set<Anlagen> anlagens = new HashSet(0);
     
     
    public Anfrage() {
    }
    
    
    public Anfrage(Beleg beleg, Karte karte, Mandant mandant, Provider provider, String anfrageNr, Date anfrageDatum, Date einkaufsDatum, BigDecimal betrag, Date fristablauf, Date insertDate, Set<Email> emails, Terminals terminals, Set<Anlagen> anlagens) {
...
    }
    
	
    public Anfrage(int anfrageId, Beleg beleg, Karte karte, Mandant mandant, Provider provider, String anfrageNr, Date einkaufsDatum, BigDecimal betrag, Date insertDate, Terminals terminals) {
...
    }
    
    
    public Anfrage(int anfrageId, Beleg beleg, Karte karte, Mandant mandant, Provider provider, String anfrageNr, Date anfrageDatum, Date einkaufsDatum, BigDecimal betrag, Date fristablauf, Date insertDate, Set<Email> emails, Terminals terminals, Set<Anlagen> anlagens) {
...
    }
    
   
    @Id 
    @Column(name="AnfrageID", unique=true, nullable=false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int getAnfrageId() {
        return this.anfrageId;
    }
    
    public void setAnfrageId(int anfrageId) {
        this.anfrageId = anfrageId;
    }
    
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="BelegID", nullable=false)
    public Beleg getBeleg() {
        return this.beleg;
    }
    
    public void setBeleg(Beleg beleg) {
        this.beleg = beleg;
    } 
    
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="KarteID", nullable=false)
    public Karte getKarte() {
        return this.karte;
    }
    
    public void setKarte(Karte karte) {
        this.karte = karte;
    } 
    
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="MandantID", nullable=false)
    public Mandant getMandant() {        
        return this.mandant;
    }
    
    public void setMandant(Mandant mandant) {
        System.out.println("MANDANT");
        this.mandant = mandant;
    }    

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="ProviderID", nullable=false)
    public Provider getProvider() {
        return this.provider;
    }
    
    public void setProvider(Provider provider) {
        this.provider = provider;
    }
    
    @Column(name="AnfrageNr", nullable=false)
    public String getAnfrageNr() {
        return this.anfrageNr;
    }
    
    public void setAnfrageNr(String anfrageNr) {
        this.anfrageNr = anfrageNr;
    }

    @Temporal(TemporalType.DATE)
    @Column(name="AnfrageDatum", length=10)
    public Date getAnfrageDatum() {
        return this.anfrageDatum;
    }
    
    public void setAnfrageDatum(Date anfrageDatum) {
        this.anfrageDatum = anfrageDatum;
    }

    @Temporal(TemporalType.DATE)
    @Column(name="EinkaufsDatum", nullable=false, length=10)
    //@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")  //TODO!!! Maybee use ONLY joda...
    public Date getEinkaufsDatum() {
        return this.einkaufsDatum;
    }
    
    public void setEinkaufsDatum(Date einkaufsDatum) {
        this.einkaufsDatum = einkaufsDatum;
    }

    
    @Column(name="Betrag", nullable=false, precision=11)
    public BigDecimal getBetrag() {
        return this.betrag;
    }
    
    public void setBetrag(BigDecimal betrag) {
        this.betrag = betrag;
    }

    @Temporal(TemporalType.DATE)
    @Column(name="Fristablauf", length=10)
    public Date getFristablauf() {
        return this.fristablauf;
    }
    
    public void setFristablauf(Date fristablauf) {
        this.fristablauf = fristablauf;
    }

    @Temporal(TemporalType.DATE)
    @Column(name="InsertDate", nullable=false, length=10)
    public Date getInsertDate() {
        return this.insertDate;
    }
    
    public void setInsertDate(Date insertDate) {
        this.insertDate = insertDate;
    }

    @OneToMany(fetch=FetchType.LAZY, mappedBy="anfrage")
    public Set<Email> getEmails() {
        return this.emails;
    }
    
    public void setEmails(Set<Email> emails) {
        this.emails = emails;
    }
    
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="TerminalsID", nullable=false)
    public Terminals getTerminals() {
        return this.terminals;
    }
    
    public void setTerminals(Terminals terminals) {
        this.terminals = terminals;
    }    
    
    @OneToMany(fetch=FetchType.LAZY, mappedBy="anfrage")
    public Set<Anlagen> getAnlagens() {
        return this.anlagens;
    }
    
    public void setAnlagens(Set<Anlagen> anlagens) {
        this.anlagens = anlagens;
    }    

    @Override
    public String toString() {
...
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + this.anfrageId;
        hash = 83 * hash + Objects.hashCode(this.beleg);
        hash = 83 * hash + Objects.hashCode(this.karte);
        hash = 83 * hash + Objects.hashCode(this.mandant);
        hash = 83 * hash + Objects.hashCode(this.provider);
        hash = 83 * hash + Objects.hashCode(this.terminals);
        hash = 83 * hash + Objects.hashCode(this.anfrageNr);
        hash = 83 * hash + Objects.hashCode(this.anfrageDatum);
        hash = 83 * hash + Objects.hashCode(this.einkaufsDatum);
        hash = 83 * hash + Objects.hashCode(this.betrag);
        hash = 83 * hash + Objects.hashCode(this.fristablauf);
        hash = 83 * hash + Objects.hashCode(this.insertDate);
        hash = 83 * hash + Objects.hashCode(this.emails);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        final Anfrage other = (Anfrage) obj;
        if (this.anfrageId != other.anfrageId) { return false; }
        if (!Objects.equals(this.beleg, other.beleg)) { return false; }
        if (!Objects.equals(this.karte, other.karte)) { return false; }
        if (!Objects.equals(this.mandant, other.mandant)) { return false; }        
        if (!Objects.equals(this.provider, other.provider)) { return false; }
        if (!Objects.equals(this.terminals, other.terminals)) { return false; }
        if (!Objects.equals(this.anfrageNr, other.anfrageNr)) { return false; }
        if (!Objects.equals(this.anfrageDatum, other.anfrageDatum)) { return false; }
        if (!Objects.equals(this.einkaufsDatum, other.einkaufsDatum)) { return false; }
        if (!Objects.equals(this.betrag, other.betrag)) { return false; }
        if (!Objects.equals(this.fristablauf, other.fristablauf)) { return false; }
        if (!Objects.equals(this.insertDate, other.insertDate)) { return false; }
        return Objects.equals(this.emails, other.emails);
    }   
}



Одна из дочерних
Код: java
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.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
@Entity
@Table(name="Mandant", schema="dbo", catalog="ReqManager")

public class Mandant implements java.io.Serializable {


    private int mandantId;
    private String nameMandant;
    private String idmandant;
    @SuppressWarnings("unchecked")
    private Set<Anfrage> anfrages = new HashSet(0);
    private String alias;

    
    public Mandant() {
    }
	
    public Mandant(int mandantId, String nameMandant, String idmandant) {
...
    }
    
    public Mandant(int mandantId, String nameMandant, String idmandant, String alias) {
...
    }
        
    public Mandant(int mandantId, String nameMandant, String idmandant, String alias, Set<Anfrage> anfrages) {
...
    }
   
    @Id    
    @Column(name="MandantID", unique=true, nullable=false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int getMandantId() {
        return this.mandantId;
    }
    
    public void setMandantId(int mandantId) {
        this.mandantId = mandantId;
    }

    
    @Column(name="NameMandant", nullable=false)
    public String getNameMandant() {
        return this.nameMandant;
    }
    
    public void setNameMandant(String nameMandant) {
        this.nameMandant = nameMandant;
    }

    
    @Column(name="IDMandant", nullable=false)
    public String getIdmandant() {
        return this.idmandant;
    }
    
    public void setIdmandant(String idmandant) {
        this.idmandant = idmandant;
    }
    
    @Column(name="Alias")
    public String getAlias() {
        return this.alias;
    }
    
    public void setAlias(String alias) {
        this.alias = alias;
    }

    @OneToMany(fetch=FetchType.LAZY, mappedBy="mandant")
    public Set<Anfrage> getAnfrages() {
        return this.anfrages;
    }
    
    public void setAnfrages(Set<Anfrage> anfrages) {
        this.anfrages = anfrages;
    }

    @Override
    public String toString() {
        if (this.getNameMandant() == null || this.getNameMandant().equals("NULL")) {
            return "Undefined"; //TODO!!! Resources
        } else {
            return this.getNameMandant();
        }
    }    

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 17 * hash + this.mandantId;
        hash = 17 * hash + Objects.hashCode(this.nameMandant);
        hash = 17 * hash + Objects.hashCode(this.idmandant);
        hash = 17 * hash + Objects.hashCode(this.alias);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        final Mandant other = (Mandant) obj;
        if (this.mandantId != other.mandantId) { return false; }
        if (!Objects.equals(this.nameMandant, other.nameMandant)) { return false; }
        if (!Objects.equals(this.idmandant, other.idmandant)) { return false; }
        return Objects.equals(this.alias, other.alias);
    }
}




Контроллер (выдержки - очень уж он уже разросся да и сыро все это пока что):
Код: java
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.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
@Component
@Scope(value = "prototype")
public class ShowSingleController implements Initializable {
        
    //GUI Objects    
    @FXML private AnchorPane showSingle;
        @FXML private HBox mainHBox;
            @FXML private VBox leftVBox;
                @FXML private HBox line1HBox;
                    @FXML private VBox line1VBox2;
                        @FXML private Label anfragedatumLabel;
                        @FXML private DatePickerWithFormatter anfragedatumPicker;      
                    @FXML private VBox line1VBox3;
                        @FXML private Label insertDatumLabel;
                        @FXML private DatePickerWithFormatter insertDatePicker;                                             
                @FXML private HBox line2HBox;
                    @FXML private VBox line2VBox1;
                        @FXML private Label terminalIDLabel;
                        @FXML private NumberTextField terminalIDTextField;
                    @FXML private VBox line2VBox2;
                        @FXML private Label storeLabel;
                        @FXML private TextField storeTextField; 
                    @FXML private VBox line2VBox3;
                        @FXML private Label fristablaufLabel;
                        @FXML private DatePickerWithFormatter fristablaufPicker;  
                @FXML private HBox line3HBox;
                    @FXML private VBox line3VBox1;
                        @FXML private Label kartennummerLabel;
                        @FXML private TextField kartennummerTextField;   
                    @FXML private VBox line3VBox2;
                        @FXML private Label ekDatumLabel;
                        @FXML private DatePickerWithFormatter ekDatumPicker; 
                    @FXML private VBox line3VBox3;    
                        @FXML private Label betragLabel;
                        @FXML private TextField betragTextField;  
                @FXML private HBox line4HBox;
                    @FXML private VBox line4VBox1;
                        @FXML private Label belegFoundLabel;
                        @FXML private DatePickerWithFormatter belegFoundDatePicker; 
                    @FXML private VBox line4VBox2;
                        @FXML private Label belegNoteLabel;
                        @FXML private TextField belegNoteTextField; 
                @FXML private HBox line5HBox;
                    @FXML private VBox line5VBox1;                
                        @FXML private Label mailSendLabel;
                        @FXML private DatePicker mailSendDatePicker;
                    @FXML private VBox line5VBox2;     
                        @FXML private Label mailConfirmLabel;
                        @FXML private TextField mailConfirmTextField;
                    @FXML private VBox line5VBox3; 
                        @FXML private Label mailRemindBuSLabel;
                        @FXML private DatePicker mailRemindBuSDatePicker;
                    @FXML private VBox line5VBox4;
                        @FXML private Label mailRemindTermLabel;
                        @FXML private DatePicker mailRemindTermDatePicker;   
                @FXML private HBox laine6HBox;
                    @FXML private Label providerLabel;
                    @FXML private ChoiceBox<Provider> providerChoiceBox;
                    @FXML private Label mandantLabel;
                    @FXML private ChoiceBox<Mandant> mandantChoiceBox;             
            @FXML private AnchorPane mailsPane;
            @FXML private AnchorPane attachmentsPane;
            @FXML private BorderPane rightBorderPane;
                @FXML private VBox errorsVBox;
                @FXML private HBox okCancelHBox;
                    @FXML private Button saveButton;
                    @FXML private Button cancelButton;
      
   ...
    //Hash of current selected Anfrage object
    private int anfrageHash;
   ...
    
    
    //Beans
    @Autowired private ProviderDAOInterface providerDAOInterface;
    @Autowired private MandantDAOInterface mandantDAOInterface;
    @Autowired private TerminalsDAOInterface terminalsDAOInterface;
    @Autowired private EntitiesUtils entitiesUtils;
    @Autowired private Locale locale;
    @Autowired private AttachmentsLayoutController attachmentsLayoutController;
    @Autowired private MailsLayoutController mailsLayoutController; 
    @Autowired private AnfrageDAOInterface anfrageDAOInterface;    
    @Autowired private AnfrageValidator anfrageValidator;
        
    
    @Override
    public void initialize(URL location, ResourceBundle resources) { 
        
        setCommonResourcesAndValues();                
        
        setActionListners();
        
        setBindingsAndProperties();

        addIncludedGUIObjects();                
    }

    
    /**
     * Show single Anfrage object
     * 
     * @param anfrageObj - Selected (null = new) Anfrage object
     * @param tableData - List of entities, shown in Table (to add new object)
     */
    public void setAnfrageItem(Anfrage anfrageObj, ObservableList<Anfrage> tableData) {       
        ...       
        fillGui(anfrageObj);
    }
    
    
    /**
     * Filled GUI with anfrage element. Sett all to null (empti) if Anfrage is null.
     * @param anfrageObj 
     */
    private void fillGui(Anfrage anfrageObj) {  
        ClearStyles();
        
        if (anfrageObj == null) {
            anfrageObj = new Anfrage(
                    new Beleg(),
                    new Karte(),
                    null,
                    null,
                    null,
                    new java.util.Date(),
                    null,
                    null,
                    null,
                    new java.util.Date(),
                    null,
                    new Terminals(),
                    null
            );
            Platform.runLater(() -> { 
                terminalIDTextField.requestFocus(); 
                providerChoiceBox.getSelectionModel().clearSelection();
                mandantChoiceBox.getSelectionModel().clearSelection();
                setGuiVisible(false);
            });
        } else {
            selectedTerminalID = anfrageObj.getTerminals().getTid().trim();
            setGuiVisible(true);
        }
        this.anfrageObj = anfrageObj;     
        this.anfrageHash = anfrageObj.hashCode();

        //***
        //Тут происходит "заполнение" объектов  полями сущности (в случае "добавить" используется этот же pane так что сущность может быть и null)
        //***
        
        attachmentsLayoutController.addInfoToGUI(anfrageObj);
    }
    
    
    /**
     * Setting action listners for GUI elements
     */
    private void setActionListners() {    
        
        //Cancel action hide this GUI
        cancelButton.setOnAction((ActionEvent e) -> {            
            System.out.println("Equal? " + (anfrageObj.hashCode()==anfrageHash));
        });
        
        //Save action
        saveButton.setOnAction((ActionEvent e) -> { 
            saveAnfrage(); 
        });
                
        //Kartennummer
        kartennummerTextField.textProperty().addListener((observable, oldValue, newValue) -> {
            anfrageObj.getKarte().setKartennummer(newValue);
            entityIsChanged.set(true);  //Это остатки моих потуг с "флагом". В принципе тоже работало, но хэш мне нравится больше.
        });

        //***
        //Далее идут аналогичные листнеры на поля
        //***
    }   
    
    
    @SuppressWarnings("unchecked")
    private boolean saveAnfrage() {
        errorsVBox.getChildren().clear();

        //1. Validate        
        BeanPropertyBindingResult result = new BeanPropertyBindingResult(anfrageObj, "Anfrage");
        ValidationUtils.invokeValidator(anfrageValidator, anfrageObj, result);
        if (result.getErrorCount() == 0) {
            anfrageDAOInterface.updateSingleElement(anfrageObj);  
            ...            
            return true;
        } else {
            List<ObjectError> allObjectErrors = result.getAllErrors();
            transitions.clear();
            for (ObjectError objectError : allObjectErrors){
               //тут "показываются" ошибки валидации  - это все идет в GUI в виде "разворачивающихся" справа от редактируемых полей labels.
            }
            return false;
        }        
    }                
    ...
}




Как-то коли кому интересно - тут наверное совсем все пока сыро вы уж сильно не пинайте:(
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303633
rdm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabВ вашем примере ресет надо будет вызывать из каждого сеттера?
Нет, один раз перед редактированием.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303637
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123ешкин кот.
- Далай один флаг на сессию а не на сущность. Зачем знать что именно изменилось?

Сорри ваш пост проглядел когда писал.
Ээээ. Ну да. Это мне и надо. Простоите за тупизм, но КАК это делается? Я искренне не понимаю что значит "флаг на сессию" и как с этим работать...
Вы ранее писали автор"Вместо того чтобы в каждой сущности сделать флаг об изменении, т.е. одно доп.поле.", что я себе представил обычным boolean, который я меняю на true в каждом сеттере, но теперь я так понимаю что я вас не так понял. Дадите ссылку где глянуть?

Спасибо!
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303642
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdmRuslanGabВ вашем примере ресет надо будет вызывать из каждого сеттера?
Нет, один раз перед редактированием.
Нет у меня немного иная логика поэтому так в моем случае не получится. При редактировании поля в контрлллере редактируется (через сеттер) поле в сущности. Полей соответственно несколько - надо либо в каждое поле либо в каждый сеттер "залезть" чтобы флаг поставить выходит. Ну или я еще сплю и совсем не понимаю что мне добрые люди донести пытаются
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303648
rdm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGab,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
entity.reset();

//
GUI редактирование

//

if(entity.isDirty()) {

}
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303652
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdmRuslanGab,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
entity.reset();

//
GUI редактирование

//

if(entity.isDirty()) {

}



понял Спасибо!!! Замучил всех совсем даже неудобно из-за таких пустяков... Решение хорошее и "родственно" моему.
Плюс моего (переопределение хэша):
- не надо добавлять ничего в "листнеры"
Плюс вашего:
- не надо переопределять хэш и удобный доступ к состоянию сущности из любого места впоследствии.
Пожалуй ваше решение лучше. Попробую с ним, правда сейчас завал на другом проекте наверное вечерком или завтра руки дойдут. Спасибо еще раз!
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303717
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGab,
решений было 2:
- хэшкод и переменная-галка в сессии Я_редактировал, вызываемая из любого листенера-события. Ты ведь всё равно их будешь писать и их у тебя 10-20 штук.
В больших системах это делается на уровне DAL - доступ к данным.
Но во-первых ты сам повырезал все слои и сказал что ты упрощаешь.
Во вторых, тут ОРМ. И у него объект равен объекту только по ID или ключу в БД.
Тут главное не смешать свой equals с тем что использует хибер.
Объект у которого в поле одна буква другая (не ключевом) хибером рассматривается как оди и тот же.
У тебя они разные.
...
Так что сам смотри. Для галки в сессии будет 10-20 строк.
Для хэша будет много больше + тестирование.
Удачи!
ЗЫ. Снимать флаг о редактировании после "поправил взад" не нужно. Это черезчур.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303725
RuslanGab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123,

Спасибо! Буду пробовать.
...
Рейтинг: 0 / 0
Как оптимально слушать изменения в сущности?
    #39303764
lleming
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RuslanGabинтересная статья, но я так и не понял чем конкретно это плохо если честно

можно случайно потерять объект в мап, причем незаметно без compile time error
...
Рейтинг: 0 / 0
25 сообщений из 26, страница 1 из 2
Форумы / Java [игнор отключен] [закрыт для гостей] / Как оптимально слушать изменения в сущности?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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