![]() |
Chirurgia endoscopică a hipofizei
"Standardul de aur" în chirurgia hipofizară îl reprezintă endoscopia transnazală transsfenoidală. Echipa NeuroHope este antrenată în unul din cele mai mari centre de chirurgie a hipofizei din Europa, Spitalul Foch din Paris, centrul în care a fost introdus pentru prima dată endoscopul în chirurgia transnazală a hipofizei, de către neurochirurgul francez Guiot. Pe lângă tumorile cu origine hipofizară, prin tehnicile endoscopice transnazale pot fi abordate numeroase alte patologii neurochirurgicale. www.neurohope.ro |
Baze de date embedded – exercitiu practic (pentru programatori mid-level)

#55
Posted 18 September 2018 - 19:57

Operatiile pe baza de date se fac cel mai bine prin repositories.
Stii/nu ai uitat de "prefer composition over inheritance", nu?
De cand cu std::string_view nu prea mai exista motive de a transmite std::string drept parametru. |
#56
Posted 18 September 2018 - 20:01

Prin repositories te referi la Repository Pattern? |
#57
Posted 18 September 2018 - 20:18

Personal prefer acest stil (cu return type-ul la final) deoarece denumirile metodelor sunt mai lizibile. Cum ĂŽn cazul metodelor care returneaza un VeryLongDataTypeName, stilul are sens, am decis să fiu constant și ĂŽn cazul celorlalte metode care returnează tipuri primitive. Exista si solutii mai simple: lasi pe un rand VeryLongDataTypeName si incepi unul nou cu numele metodei. Edited by dani.user, 18 September 2018 - 20:47. |
#58
Posted 19 September 2018 - 09:54

Cateva observatii, pe partea specifica C++:
Corect, nu am uitat. Arhitectura pe care ti-o dau e bazata pe POCO si nu am gasit o situatie in care nu e buna, poate fi suprapusa peste orice combinatie de tehnologii sau arhitecturi. E sinteza mea personala a foarte multor ani de proiecte de succes care ruleaza milioane / an, carti, articole si conferinte. Presupun ca exista proiecte facute curat de altii intr-un mod similar, dar eu nu am intalnit asa ceva pana acum in industrie. Unii POs sunt reticenti atunci cand incerci sa le "vinzi" ideea unei arhitecturi curate, deoarece au impresia ca ar costa mai mult. Eu iti arat cum poti face lucruri cu mijloace simple, pastrand codul curat, modular, si cu probabilitate de buguri mai mica. Poti promite ca nu vei sterge niciodata acel proiect si ca nu il vei redenumi (URL-ul ramane acelasi)? Ar fi extrem de util pentru cei care vin dupa tine pe aici. Follow me sau PM pentru linkedin. |
#59
Posted 19 September 2018 - 10:52

Da. Pentru început, așa ar fi OK? template <typename T, typename QueryModel> class IRepository { virtual ~IRepository() = default; virtual void add(T const& item) = 0; virtual void remove(int const id) = 0; virtual void update(int const id) = 0; virtual QueryModel search(T const& item) = 0; virtual QueryModel listAll() = 0; };
De cand cu std::string_view nu prea mai exista motive de a transmite std::string drept parametru.
Toti incearca sa iti vanda ceva, dar nimeni nu iti da o idee concreta despre cum sa faci asa incat codul sa nu fie legat ombilical de nimic. Ghidul <tehnologie aici> (ex: Qt) vrea sa faci lucrurile "the Qt way", Înțeleg la ce te referi și trebuie să îți mulțumesc pentru aceste sugestii.
Poti promite ca nu vei sterge niciodata acel proiect si ca nu il vei redenumi (URL-ul ramane acelasi)?
Follow me sau PM pentru linkedin. |
#60
Posted 19 September 2018 - 11:04

Pentru început, așa ar fi OK? |
#61
Posted 19 September 2018 - 13:45

Am introdus clasa Contact
#pragma once #include <QString> class Contact { public: constexpr Contact( QString const& lastName, QString const& firstName, QString const& phoneNumber); constexpr auto lastName() const noexcept -> QString const&; constexpr auto firstName() const noexcept -> QString const&; constexpr auto phoneNumber() const noexcept -> QString const&; private: QString _lastName; QString _firstName; QString _phoneNumber; }; inline constexpr Contact::Contact( QString const& lastName, QString const& firstName, QString const& phoneNumber) : _lastName(lastName) , _firstName(firstName) , _phoneNumber(phoneNumber) { } inline constexpr auto Contact::lastName() const noexcept -> QString const & { return _lastName; } inline constexpr auto Contact::firstName() const noexcept -> QString const & { return _firstName; } inline constexpr auto Contact::phoneNumber() const noexcept -> QString const & { return _phoneNumber; } și ContactsSQLiteRepository class ContactsSQLiteRepository : public IRepository<Contact, QSqlQueryModel*> { public: ContactsSQLiteRepository(); void add(Contact const& item) override; void remove(int const id) override; void update(Contact const& newProperties, int const id) override; QSqlQueryModel* search(Contact const& item) override; QSqlQueryModel* listAll() override; private: QSqlDatabase _database; QSqlQueryModel* _model; }; Deocamdată este OK? |
#62
Posted 19 September 2018 - 15:42

Deocamdată este OK? Returneaza obiecte Contact. Folosirea lui Qt e un detaliu de implementare al plugin-ului, nu are ce sa caute la exterior. Domain model-ul e numitorul comun al tuturor, pluginurile trebuie sa comunice in termenii din domain model. |
#63
Posted 19 September 2018 - 16:18

Înțeleg, însă UiPlugin, în stadiul actual, tot va avea cumva nevoie de un Model.
Presupun că excludem din start o relație de friendship între cele 2 plugins. Edited by jegmihai, 19 September 2018 - 16:22. |
#64
Posted 19 September 2018 - 19:20

Folosind doar API-ul C al sqlite, alaturi de biblioteca standard C++ te poate ajuta sa scrii cod mai idiomatic, cu resource management adecvat (fara pointeri membrii).
Edited by dani.user, 19 September 2018 - 19:25. |
|
#65
Posted 19 September 2018 - 20:38

Da, dar API-ul C nu poate suplini QueryModel-ul de care are nevoie View-ul.
De fapt, cred că QSqlQueryModel este singurul membru pe care am fost obligat să-l aloc pe heap din tot proiectul. Unde va fi posibil voi folosi unique_ptr. Edited by jegmihai, 19 September 2018 - 20:48. |
#66
Posted 19 September 2018 - 20:44

Daca acel querymodel e o necesitate doar pentru view, sa-si creeze viewul unul, ca detaliu intern de implementare.
|
#67
Posted 19 September 2018 - 20:51

Înțeleg, însă UiPlugin, în stadiul actual, tot va avea cumva nevoie de un Model. Ce crezi ca este Contact, daca nu un model (as in model-view-controller)? A, ca nu e stampila Qt pe el, da, nu e. E un model de model, fara bagaje suplimentare. |
#68
Posted 19 September 2018 - 22:19

Daca acel querymodel e o necesitate doar pentru view, sa-si creeze viewul unul, ca detaliu intern de implementare.
Si doar ce l-ai creat, se numeste Contact. std::vector<Contact> ContactsSQLiteRepository::search(Contact const& item) { QSqlQuery query = QueriesManager::createSearchPersonQuery(item.lastName(), item.firstName()); if (!query.exec()) throw CouldNotSearchForTheContactException(query.lastError().text().toStdString()); else { std::vector<Contact> contacts; QString lastName; QString firstName; QString phoneNumber; while (query.next()) { lastName = query.value("lastname").toString(); firstName = query.value("firstname").toString(); phoneNumber = query.value("phonenumber").toString(); Contact contact(lastName, firstName, phoneNumber); contacts.push_back(contact); } return contacts; } return std::vector<Contact>(); } În momentul în care voi lega Model-ul de View, cel din urmă nu va afișa și id-ul. Am făcut update Repository-ului de contacte. class ContactsSQLiteRepository : public IRepository<Contact> { public: ContactsSQLiteRepository(); void add(Contact const& item) override; void remove(int const id) override; void update(Contact const& newProperties, int const id) override; std::vector<Contact> search(Contact const& item) override; std::vector<Contact> listAll() override; private: QSqlDatabase _database; QSqlQueryModel* _model; }; |
#69
Posted 19 September 2018 - 22:59

Nu sună rău, însă nu știu dacă este cea mai bună soluție dpdv arhitectural. Poate ne lămurește OriginalCopy în legătură cu acest aspect. Există o problemă legată de Contact. Baza de date atribuie fiecărei înregistrări câte un id, însă Contact nu știe de acel id. Deci, dincolo de mecanismul de salvare (db sau nu), un id nu este o caracteristica intrinseca unui model-copil, ci a unui model-parinte: te ajuta sa identifici copilul in interiorul parintelui; il intrebi pe parinte: "care e copilul cu id-ul 42?", si parintele iti spune. Nu inteleg ce problema descrii de fapt. Dar avant in vedere paragraful anterior, poti descrie problema cu id-ul? Asta daca nu iti raspunde deja la intrebare... PS: copil = Contact, parinte = PhoneBook. Edited by OriginalCopy, 19 September 2018 - 22:59. |
|
#70
Posted 20 September 2018 - 08:56

Nu inteleg ce problema descrii de fapt. Dar avant in vedere paragraful anterior, poti descrie problema cu id-ul? De aici deducem că user-ul trebuie să știe de dinainte ce se află în spatele acelui id, iar acest lucru îl putea afla prin intermediul View-ului. |
#71
Posted 20 September 2018 - 09:15

Procedurile de Update și Delete au nevoie de id. De aici deducem că user-ul trebuie să știe de dinainte ce se află în spatele acelui id, iar acest lucru îl putea afla prin intermediul View-ului. A, cred că știu de unde vine neînțelegerea. Nu ai înțeles ce am scris anterior cum că eu nu aș pasa id pentru identificare, ci Contact cu totul. Iar db plugin ar ține minte intern o mapare între adresele obiectelor Contact și id-urile lor. Asta ar fi fără id in semnătură. Cu id în semnătură, filozofia ta ar fi că id-ul e o caracteristică a lui phonebook, iar metode ca search ar returna phonebook (care are un map în interior cu acele id-uri). Eu unul prefer metoda asta deoarece se potrivește mai bine cu domain model: un phonebook are contacts în el (identificate prin id-uri). Bașca că nu ne mai batem capul cu pointeri (sau un alt mecanism pe care ar trebui să îl inventăm) - path of least resistance. |
#72
Posted 20 September 2018 - 11:21

Am revenit cu un update, am adăugat noul Storage Plugin.
Am avut în vedere următoarele lucruri:
|
Anunturi
▶ 0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users