JavaRush /Java Blogu /Random-AZ /İlk Hibernate tətbiqiniz

İlk Hibernate tətbiqiniz

Qrupda dərc edilmişdir
Bu yazıda siz Java üçün ən məşhur korporativ çərçivələrdən biri ilə tanış olacaq və Hibernate-dən istifadə edərək ilk tətbiqinizi yaradacaqsınız. Hibernate haqqında heç eşitməmisiniz? Bəlkə bu haqda eşitmisiniz, amma istifadə etməmisiniz? Yoxsa başlamağa çalışdınız, amma alınmadı? Hər üç halda, kəsimə xoş gəlmisiniz :) İlk Hibernate tətbiqiniz - 1Hər kəsə salam! Bu yazıda mən Hibernate çərçivəsinin əsas xüsusiyyətlərindən danışacağam və ilk mini proqramınızı yazmağınıza kömək edəcəyəm. Bunun üçün bizə lazımdır:
  1. Intellij Idea Ultimate Edition; Rəsmi veb saytından
    yükləyin və 30 günlük sınaq versiyasını aktivləşdirin.
  2. PostgeSQL ən məşhur müasir verilənlər bazası idarəetmə sistemlərindən (DBMS) biridir;
  3. Maven (artıq IDEA-da qurulmuşdur);
  4. Bir az səbr.
Məqalə ilk növbədə bu texnologiya ilə heç vaxt işləməmiş şəxslərə yönəlib, ona görə də kodun miqdarı mümkün qədər azaldılıb. Gəlin başlayaq!

Hibernate nədir?

Bu ORM modelinin ən populyar tətbiqlərindən biridir. Obyekt-əlaqəli model proqram obyektləri və verilənlər bazasındakı qeydlər arasındakı əlaqələri təsvir edir. Əlbəttə ki, Hibernate-in funksionallığı çox genişdir, lakin biz ən sadə funksiyalara diqqət yetirəcəyik. Məqsədimiz: aşağıdakıları edə biləcək CRUD tətbiqi (Yarat, Oxu, Yenilə, Sil) yaratmaq:
  1. İstifadəçilər (İstifadəçi) yaradın, həmçinin onları şəxsiyyət vəsiqəsi ilə verilənlər bazasında axtarın, verilənlər bazasındakı məlumatlarını yeniləyin, həmçinin verilənlər bazasından silin.
  2. İstifadəçilərə avtomobil obyektlərini (Avtomatik) təyin edin. Verilənlər bazasından avtomobillər yaradın, redaktə edin, tapın və silin.
  3. Bundan əlavə, proqram avtomatik olaraq “yetim” avtomobilləri verilənlər bazasından silməlidir. Bunlar. İstifadəçi silindikdə ona məxsus bütün avtomobillər də bazadan silinməlidir.
Layihəmizin strukturu belə olacaq: İlk Hibernate tətbiqiniz - 2Gördüyünüz kimi mürəkkəb heç nə yoxdur. 6 sinif + konfiqurasiyalı 1 fayl. Əvvəlcə Intellij Idea-da yeni bir maven layihəsi yaradaq. Fayl -> Yeni Layihə. Təklif olunan layihə növlərindən Maven seçin və davam edin. İlk Hibernate tətbiqiniz - 3Apache Maven, POM dilində olan fayllarda onların strukturunun təsviri əsasında layihələrin yığılmasının avtomatlaşdırılması üçün çərçivədir. Layihənizin bütün strukturu IDEA-nın özü layihənizin kökündə yaradacağı pom.xml faylında təsvir olunacaq. Layihə parametrlərində Maven parametrlərini - groupId və artifactId-i təyin etməlisiniz. Tipik olaraq layihələrdə groupId təşkilatın və ya bölmənin adıdır və təşkilatın və ya layihə saytının domen adı orada yazılır. Öz növbəsində, artifactId layihənin adıdır. groupdId üçün təyin edə bilərsiniz com.вашНикнейм.javarush, bu heç bir şəkildə tətbiqin işinə təsir etməyəcək. ArtifactId üçün bəyəndiyiniz hər hansı bir layihə adını seçin. Siz həmçinin Versiyanı dəyişməz tərk edə bilərsiniz. İlk Hibernate tətbiqiniz - 4Sonuncu ekranda sadəcə olaraq əvvəllər daxil edilmiş məlumatlarınızı təsdiqləyin. İlk Hibernate tətbiqiniz - 5Deməli, layihəni yaratdıq, geriyə kodu yazıb işlətmək qalır :) Əvvəla, verilənlər bazası ilə işləyən proqram yaratmaq istəyiriksə, mütləq verilənlər bazası olmadan edə bilmərik! PostgreSQL-i buradan yükləyin (mən versiya 9-dan istifadə edirəm). PostgreSQL-də defolt istifadəçi "postgres" var, quraşdırma zamanı onun üçün parol yaratmalı olacaqsınız. Şifrənizi unutma, sonra bizə lazım olacaq! (Ümumiyyətlə, tətbiqlərdə standart verilənlər bazasından istifadə pis təcrübədir, lakin hemoroidlərin miqdarını azaltmaq üçün biz öz verilənlər bazamızı yaratmaqla kifayətlənəcəyik). Komanda xətti və SQL sorğuları ilə rahat deyilsinizsə, yaxşı xəbər var. Intellij IDEA verilənlər bazası ilə işləmək üçün kifayət qədər uyğun istifadəçi interfeysi təqdim edir. Bu belə görünür: İlk Hibernate tətbiqiniz - 6(IDEA-nın sağ yan panelində, Verilənlər bazası sekmesinde yerləşir) Bağlantı yaratmaq üçün “+” üzərinə klikləyin, provayderimizi (PostgeSQL) seçin. Sahələri istifadəçi, verilənlər bazası adı (hər ikisi postgres) ilə doldurun və PostgreSQL-i quraşdırarkən təyin etdiyiniz parolu daxil edin. Lazım gələrsə, Postgres sürücüsünü yükləyin, bu eyni səhifədə edilə bilər. Verilənlər bazası ilə əlaqənin qurulduğunu yoxlamaq üçün "Bağlantıyı test et" düyməsini basın. "Uğurlu" yazısını görsəniz, davam edirik. İndi bizə lazım olan cədvəlləri yaradaq. Onlardan ikisi olacaq - istifadəçilər və avtomobillər. İstifadəçilər cədvəli üçün parametrlər: Hibernate-də ilk tətbiqiniz - 7Nəzərə alın ki, id əsas açardır. SQL-də əsas açarın nə olduğunu bilmirsinizsə, Google-da axtarın, bu vacibdir. Avtomobil cədvəli üçün quraşdırma: Hibernate-də ilk tətbiqiniz - 8Avtomobillər üçün Xarici Açar - xarici açarı konfiqurasiya etməlisiniz. Cədvəllərimizi birləşdirəcək. Onun haqqında daha çox oxumağı məsləhət görürəm; Çox sadə desək, bu, xarici cədvələ, bizim vəziyyətimizdə istifadəçilərə aiddir. Əgər avtomobil id=1 olan istifadəçiyə məxsusdursa, o zaman autos cədvəlinin user_id sahəsində 1 olacaq. Biz tətbiqimizdə istifadəçiləri onların avtomobilləri ilə belə birləşdiririk. Autos cədvəlimizdə user_id sahəsi xarici açar rolunu oynayacaq. O, istifadəçilər cədvəlinin id sahəsinə istinad edəcək. İlk Hibernate tətbiqiniz - 9Beləliklə, iki cədvəldən ibarət verilənlər bazası yaratdıq. Onu Java kodundan necə idarə edəcəyini anlamaq qalır. Biz lazımi kitabxanaları daxil etməli olduğumuz pom.xml faylından başlayacağıq (Maven dilində onlara asılılıqlar deyilir). Bütün kitabxanalar mərkəzi Maven deposunda saxlanılır. Onlardan pom.xml-də qeyd etdiyinizləri layihədə istifadə edə bilərsiniz. Sizin pom.xml belə görünməlidir: İlk Hibernate tətbiqiniz - 10Gördüyünüz kimi mürəkkəb heç nə yoxdur. Biz yalnız 2 asılılıq əlavə etdik - PostgreSQL və Hibernate istifadə etmək üçün. İndi Java koduna keçək. Layihə üçün bütün lazımi paketləri və sinifləri yaradın. Başlamaq üçün bizə məlumat modelləri lazımdır - siniflər UserAuto.
package models;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table (name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    //you can not specify Column name if it matches the name of the column in the table
    private int age;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Auto> autos;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        autos = new ArrayList<>();
    }

    public void addAuto(Auto auto) {
        auto.setUser(this);
        autos.add(auto);
    }

    public void removeAuto(Auto auto) {
        autos.remove(auto);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Auto> getAutos() {
        return autos;
    }

    public void setAutos(List<Auto> autos) {
        this.autos = autos;
    }

    @Override
    public String toString() {
        return "models.User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package models;

import javax.persistence.*;

@Entity
@Table(name = "autos")
public class Auto {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column (name = "model")
    private String model;

    //you can not specify Column name if it matches the name of the column in the table
    private String color;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    public Auto() {
    }

    public Auto(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return color + " " + model;
    }
}
Gördüyünüz kimi, siniflər hələ də aydın olmayan annotasiyalarla təchiz edilmişdir. Gəlin onlarla məşğul olmağa başlayaq. Bizim üçün əsas annotasiya @Entity-dir. Bu barədə Vikipediyada oxuyun və hər şeyi xatırlayın, bu əsasların əsasıdır. Bu annotasiya sinifinizin Java obyektlərini verilənlər bazası ilə əlaqələndirməyə imkan verir. Bir sinfin müəssisə olması üçün o, aşağıdakı tələblərə cavab verməlidir:
  • Boş konstruktor olmalıdır ( publicvə ya protected);
  • İç içə, interfeys və ya ola bilməz enum;
  • -sahələr/xassələr ola bilməz finalvə ehtiva edə bilməz ;final
  • Ən azı bir @Id sahəsi olmalıdır.
Müəssisə dərslərinizi yoxlayın, bunlar özünüzü ayağınıza vurmaq üçün çox məşhur yerdir. Bir şeyi unutmaq çox asandır. Bu halda, müəssisə aşağıdakıları edə bilər:
  • Boş olmayan konstruktorları ehtiva edir;
  • Vərəsə olmaq və miras almaq;
  • Digər metodları ehtiva edin və interfeysləri həyata keçirin.
Gördüyünüz kimi, sinif Useristifadəçilər cədvəlinə çox bənzəyir. Sahələr var id, name, age. Onların üstündə yerləşən annotasiyaların çox izaha ehtiyacı yoxdur: artıq aydındır ki, @Id sahənin bu sinif obyektlərinin identifikatoru olduğunun göstəricisidir. Sinfin üstündəki @Cədvəl annotasiyası obyektlərin yazılacağı cədvəlin adını müəyyən edir. Yaş sahəsinin üstündəki şərhə diqqət yetirin: sinifdəki sahə adı və cədvəl eynidirsə, @Column annotasiyasını əlavə etmək lazım deyil, o, belə işləyəcək. Mötərizədə göstərilən “strategiya = GenerationType.IDENTITY” ilə bağlı: bir neçə ID yaratma strategiyası var. Siz onu google-da axtara bilərsiniz, amma bizim tətbiqimiz çərçivəsində narahat olmaq lazım deyil. Əsas odur ki, obyektlərimiz üçün id-lər avtomatik olaraq yaradılacaq, ona görə də id üçün təyinedici yoxdur və biz onu konstruktorda da göstərmirik. Bununla belə, sinif hələ də bəzi cəhətdən Userönə çıxır . Onun maşın siyahısı var! @OneToMany annotasiyası siyahının üstündə görünür. Bu o deməkdir ki, istifadəçi sinfinin bir obyekti bir neçə maşına uyğun gələ bilər. "mappedBY" parametri sinfin istifadəçi sahəsinə işarə edir Auto. Bu şəkildə maşınlar və istifadəçilər bir-birinə bağlıdır. OrphanRemoval parametri ingilis dilindən çox yaxşı tərcümə olunur - "yetimləri çıxarın". Bir istifadəçini verilənlər bazasından silsək, onunla əlaqəli bütün avtomobillər də silinəcək. Öz növbəsində, sinifdə Autosiz @ManyToOne annotasiyası (bir çox Avtomatlar bir İstifadəçiyə uyğun ola bilər) və @JoinColumn annotasiyası ilə istifadəçi sahəsini görəcəksiniz. İstifadəçilər cədvəli ilə əlaqənin autos cədvəlinin hansı sütunu vasitəsilə baş verdiyini göstərir (əvvəllər haqqında danışdığımız eyni xarici açar). Məlumat modeli yaratdıqdan sonra proqramımıza verilənlər bazasında bu məlumatlar üzərində əməliyyatlar aparmağı öyrətməyin vaxtı gəldi. Gəlin HibernateSessionFactoryUtil köməkçi sinifindən başlayaq. Onun yalnız bir vəzifəsi var - proqramımızın verilənlər bazası ilə işləməsi üçün sessiya fabriki yaratmaq (salam, "Zavod!" nümunəsi). Başqa heç nə edə bilməz.
package utils;

import models.Auto;
import models.User;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {
    private static SessionFactory sessionFactory;

    private HibernateSessionFactoryUtil() {}

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(User.class);
                configuration.addAnnotatedClass(Auto.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());

            } catch (Exception e) {
                System.out.println("Exception!" + e);
            }
        }
        return sessionFactory;
    }
}
Bu sinifdə biz yeni konfiqurasiya obyekti olan Konfiqurasiya yaradırıq və onun obyektlər kimi qəbul etməli olduğu sinifləri ona ötürürük - UserAuto. Metoduna diqqət yetirin configuration.getProperties(). Başqa hansı xüsusiyyətlər? Harada? Xüsusiyyətlər hibernate.cfg.xml xüsusi faylında göstərilən qışlama rejiminin necə işləməsi üçün parametrlərdir. İlk Hibernate tətbiqiniz - 11Hibernate.cfg.xml burada oxunur: new Configuration().configure(); Gördüyünüz kimi, orada xüsusi bir şey yoxdur - verilənlər bazasına qoşulma parametrləri və show_sql xüsusi parametri. Bu, bizim verilənlər bazamıza qarşı yerinə yetiriləcək qışlama rejimində olan bütün SQL sorğularının konsola çıxarılması üçün lazımdır. Beləliklə, siz Hibernate-in hər an nə etdiyini dəqiq görəcək və “sehrli” effektdən xilas olacaqsınız. Sonra bizə sinif lazımdır UserDAO. (Yaxşı mənada interfeyslər vasitəsilə proqramlaşdırmalısan - interfeys yaradıb UserDAOonu ayrıca həyata keçirməlisən UserDAOImpl, lakin kodun miqdarını azaltmaq üçün bunu buraxacağam. Bunu real layihələrdə etməyin!). DAO (məlumatlara giriş obyekti) ən çox yayılmış dizayn nümunələrindən biridir, “Data Access”. Onun mənası sadədir - tətbiqdə yalnız məlumatlara daxil olmaq üçün cavabdeh olan bir təbəqə yaratmaq, başqa heç nə yoxdur. Verilənlər bazasından məlumat alın, məlumatları yeniləyin, məlumatları silin - vəssalam. DAO-lar haqqında daha çox oxuyun; siz onları işinizdə daim istifadə edəcəksiniz. Bizim sinif nə edə bilər UserDao? Əslində, bütün DAO-lar kimi, yalnız məlumatlarla işləyə bilər. İdentifikatoru ilə istifadəçi tapın, məlumatlarını yeniləyin, silin, verilənlər bazasından bütün istifadəçilərin siyahısını çıxarın və ya yeni istifadəçini verilənlər bazasında saxlayın - bu, onun bütün funksionallığıdır.
package dao;

import models.Auto;
import models.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import utils.HibernateSessionFactoryUtil;
import java.util.List;

public class UserDao {

    public User findById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(User.class, id);
    }

    public void save(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.save(user);
        tx1.commit();
        session.close();
    }

    public void update(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.update(user);
        tx1.commit();
        session.close();
    }

    public void delete(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.delete(user);
        tx1.commit();
        session.close();
    }

    public Auto findAutoById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Auto.class, id);
    }

    public List<User> findAll() {
        List<User> users = (List<User>)  HibernateSessionFactoryUtil.getSessionFactory().openSession().createQuery("From User").list();
        return users;
    }
}
Metodlar UserDaobir-birinə bənzəyir. Onların əksəriyyətində biz Session Factory-imizdən istifadə edərək Session obyektini (verilənlər bazamıza qoşulan sessiya) alırıq, bu sessiya çərçivəsində vahid əməliyyat yaradırıq, lazımi məlumat transformasiyalarını həyata keçiririk, əməliyyatın nəticəsini verilənlər bazasında saxlayırıq və sessiyanı bağlayırıq. Metodların özləri, gördüyünüz kimi, olduqca sadədir. DAO tətbiqimizin “ürəyi”dir. Bununla belə, biz DAO-nu birbaşa yaratmayacağıq və onun üsullarını bizim main(). Bütün məntiq bu yerə köçürüləcək UserService.
package services;

import dao.UserDao;
import models.Auto;
import models.User;

import java.util.List;

public class UserService {

    private UserDao usersDao = new UserDao();

    public UserService() {
    }

    public User findUser(int id) {
        return usersDao.findById(id);
    }

    public void saveUser(User user) {
        usersDao.save(user);
    }

    public void deleteUser(User user) {
        usersDao.delete(user);
    }

    public void updateUser(User user) {
        usersDao.update(user);
    }

    public List<User> findAllUsers() {
        return usersDao.findAll();
    }

    public Auto findAutoById(int id) {
        return usersDao.findAutoById(id);
    }


}
Xidmət proqramda biznes məntiqinin icrasına cavabdeh olan məlumat təbəqəsidir. Proqramınızın bəzi biznes məntiqini yerinə yetirməsi lazımdırsa, bunu xidmətlər vasitəsilə edir. Xidmət özündə ehtiva edir UserDaovə metodlarında DAO metodlarını çağırır. Bu, sizə funksiyaların təkrarlanması kimi görünə bilər (niyə yalnız dao obyektindən metodları çağırmırsınız), lakin çox sayda obyekt və mürəkkəb məntiq ilə tətbiqi təbəqələrə bölmək böyük üstünlüklərə malikdir (bu yaxşı təcrübədir, bu məlumatı yadda saxlayın. gələcək və "tətbiq təbəqələri" haqqında oxuyun "). Xidmətimizdə məntiq sadədir, lakin real layihələrdə xidmət metodları birdən çox kod sətirindən ibarət olacaq :) İndi tətbiqin işləməsi üçün bizə lazım olan hər şey var! main()Metodda onun üçün istifadəçi və maşınlar yaradaq , onları bir-birinə bağlayaq və verilənlər bazasında saxlayaq.
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        ferrari.setUser(user);
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
    }
}
Gördüyünüz kimi, istifadəçilər cədvəlinin öz girişi, autos cədvəlinin isə öz girişi var. İlk Hibernate tətbiqiniz - 13Ваше первое приложение на Hibernate - 14Gəlin istifadəçimizin adını dəyişməyə çalışaq. İstifadəçilər cədvəlini təmizləyək və kodu işə salaq
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
    }
}
işləyir! Ваше первое приложение на Hibernate - 15Bir istifadəçini silsəniz nə olacaq? İstifadəçilər cədvəlini təmizləyək (avtomobillər özünü təmizləyəcək) və kodu icra edək
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
Və cədvəllərimiz tamamilə boşdur (konsola diqqət yetirin, Hibernate-in yerinə yetirdiyi bütün sorğular orada göstəriləcək). Siz proqramla oynaya və onun bütün xüsusiyyətlərini sınaya bilərsiniz. Məsələn, maşınları olan bir istifadəçi yaradın, onu verilənlər bazasında qeyd edin, ona hansı identifikatorun təyin olunduğuna baxın və main()bu id ilə istifadəçini verilənlər bazasından “çəkmək” və konsolda onun maşınlarının siyahısını göstərmək üçün metoddan istifadə etməyə çalışın. . Əlbəttə ki, biz Hibernate funksiyasının yalnız kiçik bir hissəsini gördük. Onun imkanları çox genişdir və çoxdan Java inkişafı üçün sənaye standartlarından biri olmuşdur. Əgər onu ətraflı öyrənmək istəyirsinizsə, əvvəlki məqalələrimdən birində nəzərdən keçirdiyim “Java Persistence API and Hibernate” kitabını tövsiyə edə bilərəm. Ümid edirəm ki, bu məqalə oxucular üçün faydalı oldu. Hər hansı bir sualınız varsa, şərhlərdə verin, məmnuniyyətlə cavablandıraram :) Həmçinin, müəllifə "Bəyən" edərək müsabiqədə dəstək olmağı unutmayın. Və ya daha yaxşısı - “Mən bunu çox bəyənirəm” :) Təhsilinizdə uğurlar!
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION