Anotasi Hibernasi - Mana yang lebih baik, bidang atau akses properti?

Jawaban:

33

Saya lebih suka accessors, karena saya dapat menambahkan beberapa logika bisnis ke accessors saya kapan pun saya butuhkan. Ini sebuah contoh:

@Entity
public class Person {

  @Column("nickName")
  public String getNickName(){
     if(this.name != null) return generateFunnyNick(this.name);
     else return "John Doe";
  }
}

Selain itu, jika Anda melempar lib lain ke dalam campuran (seperti beberapa lib konversi JSON atau BeanMapper atau Dozer atau lib pemetaan / kloning kacang lainnya berdasarkan sifat pengambil / penyetel) Anda akan memiliki jaminan bahwa lib sinkron dengan persistensi. manajer (keduanya menggunakan pengambil / penyetel).

Miguel Ping
sumber
17
Perhatikan ini tentang bagaimana ORM mengakses bidang / properti Anda dan bukan kode aplikasi Anda. Dengan akses lapangan, metode getNickName () Anda akan berfungsi persis seperti yang Anda harapkan. Hal yang sama tidak benar jika Anda menggunakan 'properti' getter / setters luar yang persisten. Di situlah Anda mungkin mengalami masalah dengan akses properti dan pemuatan yang malas. Jadi tidak, saya tidak setuju dengan argumen ini secara umum. Namun, terakhir kali saya memeriksa Hibernate memiliki masalah dengan akses bidang bidang @Id.
Rob Bygrave
11
jawaban ini tidak terkait dengan pertanyaan. Jawaban terbaik oleh
duffymo
9
seharusnya tidak ada logika bisnis di dalam accessors. itu bukan perilaku yang jelas.
iuriisusuk
Mengapa tanda respons ini benar? Tidak benar Anda dapat memetakan bidang dan menyediakannya sebagai setter / pengambil dengan cara yang sama.
Lucke
246

Ada argumen untuk keduanya, tetapi sebagian besar berasal dari persyaratan pengguna tertentu "bagaimana jika Anda perlu menambahkan logika untuk", atau "xxxx jeda enkapsulasi". Namun, tidak ada yang benar-benar berkomentar tentang teori ini, dan memberikan argumen yang beralasan.

Apa yang sebenarnya Hibernate / JPA lakukan ketika itu mempertahankan suatu objek - yah, itu mempertahankan STATE objek tersebut. Itu berarti menyimpannya dengan cara yang mudah direproduksi.

Apa itu enkapsulasi? Enkapsulasi berarti enkapsulasi data (atau status) dengan antarmuka yang dapat digunakan aplikasi / klien untuk mengakses data dengan aman - menjaganya tetap konsisten dan valid.

Pikirkan ini seperti MS Word. MS Word mempertahankan model dokumen dalam memori - NEGARA dokumen. Ini menyajikan antarmuka yang dapat digunakan pengguna untuk mengubah dokumen - satu set tombol, alat, perintah keyboard dll. Namun, ketika Anda memilih untuk bertahan (Simpan) dokumen itu, ia menyimpan keadaan internal, bukan set penekanan tombol dan klik mouse yang digunakan untuk menghasilkannya.

Menyimpan keadaan internal objek JANGAN merusak enkapsulasi - jika tidak, Anda tidak benar-benar mengerti apa arti enkapsulasi, dan mengapa itu ada. Ini seperti serialisasi objek sebenarnya.

Untuk alasan ini, DALAM KASUS PALING, itu pantas untuk tetap BIDANG dan bukan ACCESSORS. Ini berarti bahwa suatu objek dapat dibuat kembali secara akurat dari database persis seperti itu disimpan. Seharusnya tidak perlu validasi apa pun, karena ini dilakukan pada yang asli ketika dibuat, dan sebelum disimpan dalam database (kecuali, Tuhan melarang, Anda menyimpan data yang tidak valid dalam DB !!!!). Demikian juga, seharusnya tidak perlu menghitung nilai, karena mereka sudah dihitung sebelum objek disimpan. Objek harus terlihat seperti yang dilakukan sebelum disimpan. Bahkan, dengan menambahkan barang-barang tambahan ke getter / setter Anda sebenarnya meningkatkan risiko bahwa Anda akan menciptakan kembali sesuatu yang bukan salinan asli dari aslinya.

Tentu saja, fungsi ini ditambahkan karena suatu alasan. Mungkin ada beberapa kasus penggunaan yang valid untuk mempertahankan aksesor, namun biasanya jarang terjadi. Contohnya adalah Anda ingin menghindari mempertahankan nilai yang dihitung, meskipun Anda mungkin ingin mengajukan pertanyaan mengapa Anda tidak menghitungnya berdasarkan permintaan dalam pengambil nilai, atau dengan malas menginisialisasinya dalam pengambil. Secara pribadi saya tidak bisa memikirkan kasus penggunaan yang baik, dan tidak ada jawaban di sini yang benar-benar memberikan jawaban "Rekayasa Perangkat Lunak".

Martin
sumber
9
Jawaban rekayasa perangkat lunak adalah: menggunakan accessors melanggar KERING.
sourcedelica
1
@ Martin Saya memiliki pertanyaan lanjutan mengenai paragraf terakhir dari jawaban Anda. Anda menulis "Contohnya adalah Anda ingin menghindari mempertahankan nilai yang dihitung". Bagaimana Anda bisa menghindari mempertahankan nilai yang dihitung dengan memiliki akses berbasis properti? Saya tahu Anda berdebat untuk tidak melakukannya tetapi saya tidak mengerti intinya di sini. Bisakah Anda jelaskan?
Geek
4
@Geek Sekarang setelah saya baca kembali, saya sendiri tidak sepenuhnya yakin. Sudah dua tahun sejak saya menulis jawaban ini. Saya kira contoh yang lebih baik mungkin di mana Anda bekerja dengan database warisan, dan data disajikan dengan cara yang berbeda dengan model objek Anda - pengakses dapat memberikan pemetaan di antara keduanya.
Martin
23
Kasing penggunaan yang baik untuk accessor pemetaan adalah ketika Anda perlu menambahkan informasi pemetaan ke subclass dari kelas entitas pihak ketiga yang tidak terikat dengan implementasi kegigihan apa pun. Karena bidang bersifat pribadi di kelas-kelas itu, Anda harus mengganti pengakses dan menambahkan anotasi pemetaan ke dalamnya. Pilihan lain adalah menggunakan pemetaan XML, tetapi beberapa hal sangat sulit dilakukan di sana. Jadi, jika Anda ingin anotasi dan memetakan kelas pihak ketiga, subkelas mereka dan menambahkan anotasi pada pengakses adalah cara untuk pergi.
Elnur Abdurrakhimov
5
@ElnurAbdurrakhimov begitulah, contoh yang sangat bagus. Terima kasih.
Martin
79

Saya lebih suka akses bidang, karena dengan begitu saya tidak dipaksa untuk menyediakan pengambil / penyetel untuk setiap properti.

Survei cepat melalui Google menunjukkan bahwa akses bidang adalah yang terbanyak (mis., Http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype ).

Saya percaya akses lapangan adalah idiom yang direkomendasikan oleh Spring, tetapi saya tidak dapat menemukan referensi untuk mendukungnya.

Ada pertanyaan SO terkait yang mencoba mengukur kinerja dan sampai pada kesimpulan bahwa "tidak ada perbedaan".

Duffymo
sumber
jika Anda tidak memberikan pengambil setter dalam entitas lalu apa gunanya bidang itu ... Anda tidak dapat menggunakannya di mana pun dalam aplikasi, karena bidang bersifat pribadi
anshulkatta
1
Tidak menyediakan pengambil dan penyetel untuk bidang Anda praktik buruk ?, saya kira komentar saya di sini tidak selalu benar, karena saya mengasumsikan bidang publik, sementara itu jelas bisa menjadi bidang pribadi yang tidak pernah diakses.
Mathijs Segers
3
@anshulkatta Saya merasa saya harus benar-benar menjawab pertanyaan Anda, karena itu adalah enkapsulasi. Idealnya semua bidang Anda harus pribadi, dan jika mungkin mereka tidak memiliki getter atau setter - itu adalah tingkat enkapsulasi terbaik yang dapat Anda harapkan. Pertimbangkan pemeriksa kata sandi. 2 bidang pribadi, kata sandi, hash dan percobaan gagal. Keduanya bisa bersifat pribadi tanpa pengambil atau penyetel. Mereka digunakan oleh bool checkPassword (kata sandi string) yang hash, memeriksa terhadap passwordHash dan kemudian memperbarui Gagal mencoba dan mengembalikan hasilnya. Tidak perlu kode lain untuk mengakses kedua bidang tersebut.
Martin
2
@anshulkatta harus dicatat bahwa dalam OOP, getter dan setter adalah anti-pola, mereka berasal dari pemrograman prosedural, memiliki kelas dengan mereka melanggar prinsip enkapsulasi, dan menghasilkan banyak kode boilerplate, yaitu, jenis yang sama dari kode berulang-ulang. Objek harus tidak berubah, jika diperlukan modifikasi properti, harus dilakukan melalui metode yang melakukan sesuatu lebih dari sekadar mengembalikan nilai properti.
Uriel Arvizu
Tidak begitu. "Anti-pola" dalam hal ini adalah masalah pendapat, bukan dogma. Dengan demikian, akses bidang masih lebih disukai. Ide yang lebih baik adalah menghindar dari solusi ORM sama sekali. Pelajari cara menulis SQL yang tepat.
duffymo
38

Berikut adalah situasi di mana Anda HARUS menggunakan aksesor properti. Bayangkan Anda memiliki kelas abstrak GENERIC dengan banyak implementasi kebaikan untuk diwariskan ke dalam 8 subkelas beton:

public abstract class Foo<T extends Bar> {

    T oneThing;
    T anotherThing;

    // getters and setters ommited for brevity

    // Lots and lots of implementation regarding oneThing and anotherThing here
 }

Sekarang tepatnya bagaimana Anda membubuhi keterangan kelas ini? Jawabannya adalah ANDA TIDAK BISA membubuhi keterangan sama sekali dengan bidang atau akses properti karena Anda tidak dapat menentukan entitas target pada saat ini. Anda HARUS membuat anotasi implementasi konkret. Tetapi karena properti yang bertahan dideklarasikan dalam superclass ini, Anda HARUS menggunakan akses properti di subclass.

Akses lapangan bukan merupakan opsi dalam aplikasi dengan superkelas generik abstrak.

HDave
sumber
2
menyentuh. Saya tidak memikirkan itu. Saya yakin Hibernate mengeluarkan beberapa sql gila untuk ini.
Joseph Lust
8
Masalah ini kedengarannya sulit secara mekanis untuk dipecahkan tanpa membuat anotasi properti, tetapi saya belum pernah menemukan kasus di mana saya membutuhkan kelas generik abstrak dengan banyak implementasi yang juga ingin saya pertahankan. Biasanya saya membuat hierarki kelas untuk membuat objek saya polimorfik (yang membuatnya menjadi semacam jeda generik), dan tidak hanya untuk penggunaan kembali kode. Dan "banyak dan banyak implementasi" sering melanggar SRP, dalam hal ini saya mungkin akan memindahkannya ke kelas yang terpisah. Apakah ada contoh nyata yang membuat use case ini lebih jelas?
Merlyn Morgan-Graham
Satu-satunya contoh nyata yang saya miliki adalah aplikasi saya, yang saya tidak dapat uraikan dalam komentar 500 karakter ;-)
HDave
3
Anda dapat menggunakan abstract T getOneThing(), dan abstract void setOneThing(T thing), dan menggunakan akses bidang.
Arturo Volpe
33

Saya cenderung lebih suka dan menggunakan aksesor properti:

  • Saya dapat menambahkan logika jika diperlukan (sebagaimana disebutkan dalam jawaban yang diterima).
  • itu memungkinkan saya untuk menelepon foo.getId() tanpa menginisialisasi proxy (penting saat menggunakan Hibernate, sampai HHH-3718 diselesaikan).

Kekurangan:

  • itu membuat kode kurang mudah dibaca, misalnya Anda harus menelusuri seluruh kelas untuk melihat apakah ada di @Transientsekitar sana.
Thivent Pascal
sumber
tetapi kemudian jika Anda menggunakan penyedia JPA yang tidak memiliki "proxy" maka Anda tidak memiliki masalah itu alias "penyedia JPA Anda memaksakan pada Anda".
Neil Stockton
13

Itu benar-benar tergantung pada kasus tertentu - kedua opsi tersedia karena suatu alasan. IMO itu bermuara pada tiga kasus:

  1. setter memiliki beberapa logika yang tidak boleh dieksekusi pada saat memuat instance dari database; misalnya, beberapa validasi nilai terjadi pada setter, namun data yang berasal dari db harus valid (jika tidak maka tidak akan sampai di sana (:); dalam hal ini akses lapangan paling tepat;
  2. setter memiliki beberapa logika yang harus selalu dipanggil, bahkan saat memuat instance dari db; misalnya, properti yang diinisialisasi digunakan dalam perhitungan beberapa bidang yang dihitung (misalnya properti - jumlah moneter, properti terhitung - total beberapa properti moneter dari contoh yang sama); dalam hal ini diperlukan akses properti.
  3. Tak satu pun dari kasus di atas - maka kedua opsi berlaku, tetap konsisten (mis. Jika akses lapangan adalah pilihan dalam situasi ini, maka gunakan sepanjang waktu dalam situasi yang sama).
01es
sumber
Saya baru mengenal Hibernate dan berjuang dengan pertanyaan yang sama. Saya pikir posting ini memberikan jawaban yang paling jelas. Terima kasih.
Sam Levin
12

Saya akan sangat menyarankan akses bidang dan BUKAN anotasi pada getter (akses properti) jika Anda ingin melakukan sesuatu yang lebih dalam setter daripada hanya mengatur nilai (misalnya Enkripsi atau perhitungan).

Masalah dengan akses properti adalah bahwa setter juga dipanggil ketika objek dimuat. Ini telah berhasil bagi saya selama berbulan-bulan sampai kami ingin memperkenalkan enkripsi. Dalam kasus penggunaan kami, kami ingin mengenkripsi bidang dalam setter dan mendekripsi dalam pengambil. Masalahnya sekarang dengan akses properti adalah bahwa ketika Hibernate memuat objek itu juga memanggil setter untuk mengisi bidang dan dengan demikian mengenkripsi nilai terenkripsi lagi. Posting ini juga menyebutkan ini: Java Hibernate: Perilaku fungsi kumpulan properti yang berbeda tergantung pada siapa yang memanggilnya

Ini telah menyebabkan saya sakit kepala sampai saya ingat perbedaan antara akses lapangan dan akses properti. Sekarang saya telah memindahkan semua anotasi saya dari akses properti ke akses lapangan dan berfungsi dengan baik sekarang.

Christoph
sumber
Ya - Saya telah menemukan bahwa jika Anda menggunakan akses properti Anda benar-benar tidak dapat melakukan apa pun di setter Anda selain menetapkan nilai bidang.
HDave
2
+1 Jauhkan dari getter / setter. Saya menggunakan projectlombok.org dan menyembunyikannya dari pengembang.
bhantol
11

Saya lebih suka menggunakan akses lapangan karena alasan berikut:

  1. The akses properti dapat menyebabkan bug yang sangat jahat ketika menerapkan equals / hashCode dan referensi bidang langsung (sebagai lawan melalui getter mereka). Ini karena proxy hanya diinisialisasi ketika getter diakses, dan akses bidang langsung hanya akan mengembalikan nol.

  2. The akses properti mengharuskan Anda untuk membubuhi keterangan semua metode utilitas (misalnya addChild / removeChild) sebagai @Transient.

  3. Dengan akses bidang kita bisa menyembunyikan bidang @Version dengan tidak mengekspos pengambil sama sekali. Seorang pengambil juga dapat menyebabkan menambahkan setter juga, dan versionbidang tidak boleh diatur secara manual (yang dapat menyebabkan masalah yang sangat buruk). Semua peningkatan versi harus dipicu melalui OPTIMISTIC_FORCE_INCREMENT atau PESSIMISTIC_FORCE_INCREMENT penguncian eksplisit.

Vlad Mihalcea
sumber
1. Bagaimana strategi akses lapangan mencegah hal ini? Ini tampaknya menjadi perangkap umum dengan proxy, terlepas dari gaya aksesnya. 2. Apakah Anda yakin, apakah itu hanya pengambil keperluan? (Tapi argumen yang bagus pula). 3. Mengekspos pengakses untuk versionbidang sering berguna dalam situasi di mana DTO digunakan sebagai pengganti entitas yang terpisah.
Dragan Bozanovic
1. Karena saat Proxy diinisialisasi. 2. 100% yakin. 3. Itu poin yang valid.
Vlad Mihalcea
Maafkan ketidaktahuan saya dan kemungkinan kurangnya interpretasi teks, (Saya bukan penutur asli bahasa Inggris). Hanya untuk memperjelas, akses lapangan adalah ketika tidak ada metode pengambil / penyetel yang diperlukan, jadi untuk POJO, yang digunakan secara holistik, bidangnya publik? Tapi Anda mengatakan sesuatu dalam topik pertama dan posting blog yang terhubung mengatakan sebaliknya. Apa yang saya mengerti adalah bahwa Anda tidak dapat menggunakan yang sama ketika menggunakan proxy dan akses bidang.
MaikoID
Tidak. Akses bidang berarti Hibernate menggunakan bidang melalui refleksi untuk membaca atribut entitas. Untuk detail lebih lanjut, lihat bagian Jenis Akses di Panduan Pengguna Hibernate .
Vlad Mihalcea
7

Saya pikir annotating properti lebih baik karena memperbarui bidang secara langsung memecah enkapsulasi, bahkan ketika ORM Anda melakukannya.

Berikut ini adalah contoh yang bagus dari mana ia akan membakar Anda: Anda mungkin ingin anotasi Anda untuk hibernate validator & kegigihan di tempat yang sama (baik bidang atau properti). Jika Anda ingin menguji validasi bertenaga validator hibernate yang dianotasi pada bidang, Anda tidak bisa menggunakan tiruan entitas Anda untuk mengisolasi unit test Anda menjadi validator saja. Aduh.

Justin Standard
sumber
2
Itulah mengapa Anda menaruh anotasi validator pada pengakses dan anotasi kegigihan di bidang
fishbone
6

Saya percaya akses properti vs akses lapangan agak berbeda sehubungan dengan inisialisasi malas.

Pertimbangkan pemetaan berikut untuk 2 kacang polong:

<hibernate-mapping package="org.nkl.model" default-access="field">
  <class name="FieldBean" table="FIELD_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

<hibernate-mapping package="org.nkl.model" default-access="property">
  <class name="PropBean" table="PROP_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

Dan tes unit berikut:

@Test
public void testFieldBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    FieldBean fb = new FieldBean("field");
    Long id = (Long) session.save(fb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    fb = (FieldBean) session.load(FieldBean.class, id);
    System.out.println(fb.getId());
    tx.commit();
    session.close();
}

@Test
public void testPropBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    PropBean pb = new PropBean("prop");
    Long id = (Long) session.save(pb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    pb = (PropBean) session.load(PropBean.class, id);
    System.out.println(pb.getId());
    tx.commit();
    session.close();
}

Anda akan melihat perbedaan halus dalam pemilihan yang diperlukan:

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        FIELD_BEAN
        (message, id) 
    values
        (?, ?)
Hibernate: 
    select
        fieldbean0_.id as id1_0_,
        fieldbean0_.message as message1_0_ 
    from
        FIELD_BEAN fieldbean0_ 
    where
        fieldbean0_.id=?
0
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        PROP_BEAN
        (message, id) 
    values
        (?, ?)
1

Artinya, panggilan fb.getId()membutuhkan pilih, sedangkan pb.getId()tidak.

toolkit
sumber
Ini lucu! :) Tetapi ini adalah perilaku khusus implementasi, saya yakin. I
Vladimir Dyuzhev
Ya, saya kira ini karena fakta bahwa hanya kelas persisten yang diinstrumentasi. Namun ini sangat menyebalkan karena bidang id seringkali merupakan bidang yang tidak memiliki nilai bisnis dan tidak memerlukan pengakses apa pun.
Maurice Perry
6

Biarkan saya mencoba merangkum alasan paling penting untuk memilih akses berbasis lapangan. Jika Anda ingin menyelam lebih dalam, baca artikel ini di blog saya: Strategi Akses di JPA dan Hibernate - Mana yang lebih baik, akses bidang atau properti?

Akses berbasis lapangan sejauh ini merupakan pilihan yang lebih baik. Berikut 5 alasan untuk itu:

Alasan 1: keterbacaan kode Anda lebih baik

Jika Anda menggunakan akses berbasis bidang, Anda memberi anotasi atribut entitas Anda dengan anotasi pemetaan Anda. Dengan menempatkan definisi semua atribut entitas di bagian atas kelas Anda, Anda mendapatkan tampilan yang relatif kompak dari semua atribut dan pemetaannya.

Alasan 2: Hapus metode pengambil atau penyetel yang tidak boleh dipanggil oleh aplikasi Anda

Keuntungan lain dari akses berbasis lapangan adalah bahwa penyedia ketekunan Anda, misalnya, Hibernate atau EclipseLink, tidak menggunakan metode pengambil dan penyetel atribut entitas Anda. Itu berarti Anda tidak perlu memberikan metode apa pun yang tidak boleh digunakan oleh kode bisnis Anda. Ini paling sering terjadi pada metode setter dari atribut primary key atau kolom versi yang dihasilkan . Penyedia ketekunan Anda mengelola nilai atribut ini, dan Anda tidak harus mengaturnya secara terprogram.

Alasan 3: Implementasi metode pengambil dan penyetel yang fleksibel

Karena penyedia kegigihan Anda tidak memanggil metode pengambil dan penyetel, mereka tidak dipaksa untuk memenuhi persyaratan eksternal apa pun. Anda dapat menerapkan metode ini dengan cara apa pun yang Anda inginkan. Itu memungkinkan Anda untuk menerapkan aturan validasi khusus bisnis, untuk memicu logika bisnis tambahan atau untuk mengubah atribut entitas menjadi tipe data yang berbeda.

Anda dapat, misalnya, menggunakannya untuk membungkus asosiasi opsional atau atribut menjadi Java Optional.

Alasan 4: Tidak perlu menandai metode utilitas sebagai @Transient

Manfaat lain dari strategi akses berbasis lapangan adalah Anda tidak perlu membuat anotasi dengan metode utilitas Anda @Transient. Anotasi ini memberi tahu penyedia ketekunan Anda bahwa metode atau atribut bukan bagian dari status persisten entitas. Dan karena dengan akses tipe bidang status persisten akan ditentukan oleh atribut entitas Anda, implementasi JPA Anda mengabaikan semua metode entitas Anda.

Alasan 5: Hindari bug saat bekerja dengan proxy

Hibernate menggunakan proksi untuk secara malas mengambil ke-satu asosiasi sehingga dapat mengontrol inisialisasi asosiasi ini. Pendekatan itu bekerja dengan baik di hampir semua situasi. Tapi itu menimbulkan jebakan berbahaya jika Anda menggunakan akses berbasis properti.

Jika Anda menggunakan akses berbasis properti, Hibernate menginisialisasi atribut objek proxy ketika Anda memanggil metode pengambil. Itu selalu terjadi jika Anda menggunakan objek proxy dalam kode bisnis Anda. Tetapi cukup banyak implementasi yang sama dan hashCode mengakses atribut secara langsung. Jika ini adalah pertama kalinya Anda mengakses salah satu atribut proksi, atribut ini masih belum diinisialisasi.

Thorben Janssen
sumber
3

Secara default, penyedia JPA mengakses nilai-nilai bidang entitas dan memetakan bidang-bidang tersebut ke kolom basis data menggunakan metode accessor (getter) properti JavaBean dan metode mutator (setter). Dengan demikian, nama dan tipe bidang pribadi dalam suatu entitas tidak menjadi masalah bagi JPA. Alih-alih, JPA hanya melihat nama dan mengembalikan tipe pengakses properti JavaBean. Anda dapat mengubah ini menggunakan @javax.persistence.Accessanotasi, yang memungkinkan Anda untuk secara eksplisit menentukan metodologi akses yang harus digunakan penyedia JPA.

@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}

Pilihan yang tersedia untuk AccessType enum adalah PROPERTI (standar) dan FIELD. Dengan PROPERTI, penyedia mendapat dan menetapkan nilai bidang menggunakan metode properti JavaBean. FIELD membuat penyedia mendapatkan dan menetapkan nilai bidang menggunakan bidang contoh. Sebagai praktik terbaik, Anda harus tetap berpegang pada default dan menggunakan properti JavaBean kecuali Anda memiliki alasan kuat untuk melakukan sebaliknya.

Anda dapat menempatkan anotasi properti ini di bidang pribadi atau metode pengakses publik. Jika Anda menggunakan AccessType.PROPERTY(default) dan membubuhi keterangan bidang pribadi alih-alih aksesor JavaBean, nama bidang harus cocok dengan nama properti JavaBean. Namun, nama tidak harus cocok jika Anda memberi anotasi pada pengakses JavaBean. Demikian juga, jika Anda menggunakan AccessType.FIELDdan memberi anotasi pengakses JavaBean alih-alih bidang, nama bidang juga harus cocok dengan nama properti JavaBean. Dalam hal ini, mereka tidak harus cocok jika Anda memberi anotasi pada bidang. Yang terbaik adalah konsisten dan membuat anotasi untuk JavaBean AccessType.PROPERTYdan bidang untuk AccessType.FIELD.

Adalah penting bahwa Anda tidak boleh mencampur anotasi properti JPA dan anotasi bidang JPA dalam entitas yang sama. Melakukannya menghasilkan perilaku yang tidak ditentukan dan sangat mungkin menyebabkan kesalahan.

Faraz
sumber
2

Apakah kita sudah sampai

Itu presentasi lama tetapi Rod menyarankan bahwa anotasi pada akses properti mendorong model domain anemia dan tidak boleh menjadi cara "default" untuk membuat anotasi.

Manuel Palacio
sumber
2

Hal lain yang mendukung akses bidang adalah bahwa jika tidak, Anda dipaksa untuk mengekspos setter untuk koleksi juga, bagi saya, adalah ide yang buruk karena mengubah instance koleksi persisten ke objek yang tidak dikelola oleh Hibernate pasti akan merusak konsistensi data Anda.

Jadi saya lebih suka memiliki koleksi sebagai bidang yang dilindungi diinisialisasi ke implementasi kosong di konstruktor default dan hanya mengekspos getter mereka. Operasi itu, hanya berhasil seperti clear(), remove(), removeAll()dll adalah mungkin bahwa tidak akan pernah membuat Hibernate tidak menyadari perubahan.

Ji Ví Vypědřík
sumber
Anda tidak dipaksa untuk mengekspos apa pun karena setter dapat dilindungi. Selain itu, setter tersebut bukan bagian dari antarmuka yang diimplementasikan sehingga meskipun publik, mereka tidak mudah diakses.
HDave
2

Saya lebih suka bidang, tapi saya pernah mengalami satu situasi yang tampaknya memaksa saya untuk menempatkan anotasi pada pengambil.

Dengan implementasi Hibernate JPA, @Embeddedsepertinya tidak berfungsi di bidang. Jadi itu harus pergi pada rajin dan giat. Dan begitu Anda meletakkannya di rajin, maka berbagai @Columnanotasi juga harus di rajin . (Saya pikir Hibernate tidak ingin mencampur bidang dan getter di sini.) Dan begitu Anda memakai @Columngetter dalam satu kelas, mungkin masuk akal untuk melakukan itu sepanjang.


sumber
2

Saya menyukai pengakses lapangan. Kode jauh lebih bersih. Semua anotasi dapat ditempatkan di satu bagian kelas dan kodenya lebih mudah dibaca.

Saya menemukan masalah lain dengan accessors properti: jika Anda memiliki metode getXYZ di kelas Anda yang TIDAK dianotasi terkait dengan properti persisten, hibernate menghasilkan sql untuk mencoba mendapatkan properti tersebut, menghasilkan beberapa pesan kesalahan yang sangat membingungkan. Dua jam terbuang. Saya tidak menulis kode ini; Saya selalu menggunakan pengakses lapangan di masa lalu dan tidak pernah mengalami masalah ini.

Versi hibernasi yang digunakan dalam aplikasi ini:

<!-- hibernate -->
<hibernate-core.version>3.3.2.GA</hibernate-core.version>
<hibernate-annotations.version>3.4.0.GA</hibernate-annotations.version>
<hibernate-commons-annotations.version>3.1.0.GA</hibernate-commons-annotations.version>
<hibernate-entitymanager.version>3.4.0.GA</hibernate-entitymanager.version>
John Goyer
sumber
2

Anda harus memilih akses melalui bidang daripada akses melalui properti. Dengan bidang Anda dapat membatasi data yang dikirim dan diterima. Dengan via properti, Anda dapat mengirim lebih banyak data sebagai tuan rumah, dan mengatur denominasi G (pabrik yang mengatur sebagian besar properti secara total).

pengguna10801787
sumber
1

Saya memiliki pertanyaan yang sama mengenai accesstype di hibernate dan menemukan beberapa jawaban di sini .

jam matahari
sumber
1

Kami membuat kacang entitas dan menggunakan anotasi pengambil. Masalah yang kami hadapi adalah ini: beberapa entitas memiliki aturan kompleks untuk beberapa properti mengenai kapan mereka dapat diperbarui. Solusinya adalah memiliki beberapa logika bisnis di setiap penyetel yang menentukan apakah nilai aktual berubah atau tidak, dan jika demikian, apakah perubahan tersebut harus diizinkan. Tentu saja, Hibernate selalu dapat mengatur properti, jadi kami berakhir dengan dua kelompok setter. Cukup jelek.

Membaca posting sebelumnya, saya juga melihat bahwa referensi properti dari dalam entitas dapat menyebabkan masalah dengan koleksi yang tidak dimuat.

Intinya, saya akan condong ke arah anotasi bidang di masa depan.

Steve11235
sumber
0

Biasanya kacang adalah POJO, jadi mereka tetap memiliki aksesor.

Jadi pertanyaannya bukan "mana yang lebih baik?", Tetapi hanya "kapan harus menggunakan akses lapangan?". Dan jawabannya adalah "ketika Anda tidak membutuhkan setter / pengambil untuk bidang!".

Vladimir Dyuzhev
sumber
4
Masalahnya adalah bahwa Anda tidak dapat mencampur akses bidang dan akses properti di POJO - Anda harus memilih satu
Martin OConnor
Betulkah? Aku pasti sudah melupakannya. Lagi pula, saya selalu menggunakan POJO dan aksesor.
Vladimir Dyuzhev
Perhatikan bahwa dengan JPA 2.0 (yang tidak ada ketika pertanyaan ini diajukan) Anda sekarang dapat mencampur jenis akses menggunakan anotasi @AccessType.
mtpettyp
0

Saya memikirkan hal ini dan saya memilih metode accesor

Mengapa?

karena bidang dan metos accesor adalah sama tetapi jika nanti saya memerlukan beberapa logika di bidang beban, saya menyimpan semua anotasi memindahkan ditempatkan di bidang

salam

Grubhart

pengguna261548
sumber
0

Untuk membuat kelas Anda lebih bersih, letakkan anotasi di bidang lalu gunakan @Access (AccessType.PROPERTY)

Ely
sumber
0

AccessType.PROPERTY: Implementasi EJB yang persisten akan memuat status ke kelas Anda melalui metode "setter" JavaBean, dan mengambil status dari kelas Anda menggunakan metode "pengambil" JavaBean. Ini standarnya.

AccessType.FIELD: Negara dimuat dan diambil langsung dari bidang kelas Anda. Anda tidak harus menulis "getter" dan "setter" JavaBean.

Daria Yu
sumber