Chú thích ngủ đông - Cái nào tốt hơn, truy cập trường hoặc thuộc tính?


Câu trả lời:


33

Tôi thích người truy cập hơn, vì tôi có thể thêm một số logic kinh doanh cho người truy cập của mình bất cứ khi nào tôi cần. Đây là một ví dụ:

@Entity
public class Person {

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

Ngoài ra, nếu bạn ném các lib khác vào hỗn hợp (như một số lib chuyển đổi JSON hoặc BeanMapper hoặc Dozer hoặc lib ánh xạ / sao chép đậu khác dựa trên các thuộc tính getter / setter), bạn sẽ đảm bảo rằng lib được đồng bộ hóa với tính bền vững người quản lý (cả hai đều sử dụng getter / setter).


17
Lưu ý đây là về cách ORM truy cập vào các trường / thuộc tính của bạn chứ không phải mã ứng dụng của bạn. Với trường truy cập, phương thức getNickName () của bạn sẽ hoạt động chính xác như bạn mong đợi. Điều này cũng không đúng nếu bạn sử dụng 'thuộc tính' liên tục bên ngoài getters / setters. Đó là nơi bạn có thể gặp vấn đề với quyền truy cập tài sản và lười tải. Vì vậy, không, tôi không đồng ý với lập luận này nói chung. Tuy nhiên, lần trước tôi đã kiểm tra Hibernate có vấn đề với quyền truy cập trường của các trường @Id.
Rob Bygrave

11
Câu trả lời này không liên quan đến câu hỏi. Câu trả lời hay nhất của
duffymo

9
không nên có bất kỳ logic kinh doanh nào trong các bộ truy cập. Đó không phải là hành vi rõ ràng.
iuriisusuk

Tại sao dấu phản hồi này là chính xác? Không đúng khi bạn có thể ánh xạ trường và cung cấp cho nó một setter / getter theo cùng một cách.
Lucke

246

Có các đối số cho cả hai, nhưng hầu hết trong số chúng xuất phát từ một số yêu cầu người dùng nhất định "nếu bạn cần thêm logic cho" hoặc "xxxx phá vỡ đóng gói". Tuy nhiên, không ai thực sự bình luận về lý thuyết này, và đưa ra một lập luận hợp lý.

Hibernate / JPA thực sự đang làm gì khi nó tồn tại một đối tượng - tốt, nó vẫn tồn tại NHÀ NƯỚC của đối tượng. Điều đó có nghĩa là lưu trữ nó theo cách mà nó có thể dễ dàng sao chép.

Đóng gói là gì? Đóng gói có nghĩa là đóng gói dữ liệu (hoặc trạng thái) với giao diện mà ứng dụng / khách hàng có thể sử dụng để truy cập dữ liệu một cách an toàn - giữ cho dữ liệu nhất quán và hợp lệ.

Hãy nghĩ về điều này giống như MS Word. MS Word duy trì một mô hình của tài liệu trong bộ nhớ - tài liệu STATE. Nó trình bày một giao diện mà người dùng có thể sử dụng để sửa đổi tài liệu - một bộ nút, công cụ, lệnh bàn phím, v.v. Tuy nhiên, khi bạn chọn duy trì (Lưu) tài liệu đó, nó sẽ lưu trạng thái bên trong, chứ không phải tập hợp các phím bấm và nhấp chuột được sử dụng để tạo ra nó.

Lưu trạng thái bên trong của đối tượng KHÔNG phá vỡ đóng gói - nếu không, bạn không thực sự hiểu đóng gói nghĩa là gì và tại sao nó tồn tại. Nó giống như tuần tự hóa đối tượng thực sự.

Vì lý do này, TRONG CÁC TRƯỜNG HỢP NHẤT, thích hợp để duy trì các L FINH VỰC chứ không phải PHỤ KIỆN. Điều này có nghĩa là một đối tượng có thể được tạo lại chính xác từ cơ sở dữ liệu chính xác theo cách nó được lưu trữ. Nó không cần bất kỳ xác nhận nào, bởi vì điều này đã được thực hiện trên bản gốc khi nó được tạo và trước khi nó được lưu trữ trong cơ sở dữ liệu (trừ khi, Chúa cấm, bạn đang lưu trữ dữ liệu không hợp lệ trong DB !!!!). Tương tự như vậy, không cần phải tính toán các giá trị, vì chúng đã được tính toán trước khi đối tượng được lưu trữ. Đối tượng nên nhìn giống như cách nó đã làm trước khi nó được lưu. Trong thực tế, bằng cách thêm các công cụ bổ sung vào getters / setters, bạn thực sự làm tăng nguy cơ rằng bạn sẽ tạo lại một cái gì đó không phải là bản sao chính xác của bản gốc.

Tất nhiên, chức năng này đã được thêm vào vì một lý do. Có thể có một số trường hợp sử dụng hợp lệ để duy trì người truy cập, tuy nhiên, chúng thường sẽ rất hiếm. Một ví dụ có thể là bạn muốn tránh duy trì một giá trị được tính toán, mặc dù bạn có thể muốn đặt câu hỏi tại sao bạn không tính toán nó theo yêu cầu trong getter của giá trị, hoặc khởi tạo một cách lười biếng trong getter. Cá nhân tôi không thể nghĩ ra bất kỳ trường hợp sử dụng tốt nào và không có câu trả lời nào ở đây thực sự đưa ra câu trả lời "Kỹ thuật phần mềm".


9
Câu trả lời về kỹ thuật phần mềm là: sử dụng các bộ truy cập vi phạm DRY.
sourcedelica

1
@Martin Tôi có một câu hỏi tiếp theo liên quan đến đoạn cuối của câu trả lời của bạn. Bạn đã viết "Một ví dụ có thể là bạn muốn tránh duy trì giá trị tính toán". Làm thế nào bạn có thể tránh việc duy trì một giá trị được tính bằng cách có quyền truy cập dựa trên tài sản? Tôi biết bạn đang tranh luận không làm như vậy nhưng tôi không nhận được điểm ở đây. Bạn có thể giải thích dùm không?
Geek

4
@Geek Bây giờ tôi đọc lại tôi không hoàn toàn chắc chắn về bản thân mình. Đã hai năm kể từ khi tôi viết câu trả lời này. Tôi đoán một ví dụ tốt hơn có thể là nơi bạn đang làm việc với cơ sở dữ liệu cũ và dữ liệu được trình bày theo cách khác với mô hình đối tượng của bạn - người truy cập có thể cung cấp ánh xạ giữa hai cơ sở.
Martin

23
Một trường hợp sử dụng tốt để truy cập ánh xạ là khi bạn cần thêm thông tin ánh xạ vào các lớp con của các lớp thực thể của bên thứ ba không bị ràng buộc với bất kỳ triển khai kiên trì nào. Vì các trường là riêng tư trong các lớp đó, bạn phải ghi đè người truy cập và thêm chú thích ánh xạ vào chúng. Một tùy chọn khác là sử dụng ánh xạ XML, nhưng một số điều rất khó thực hiện ở đó. Vì vậy, nếu bạn muốn chú thích và ánh xạ các lớp của bên thứ ba, phân lớp chúng và thêm chú thích trên các bộ truy cập là cách tốt nhất.
Elnur Abdurrakhimov

5
@ElnurAbdurrakhimov chúng ta đi, một ví dụ tuyệt vời. Cảm ơn.
Martin

79

Tôi thích truy cập trường hơn, vì theo cách đó tôi không bị buộc phải cung cấp getter / setter cho mỗi thuộc tính.

Một khảo sát nhanh qua Google cho thấy rằng quyền truy cập trường chiếm đa số (ví dụ: http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype ).

Tôi tin rằng truy cập trường là thành ngữ được đề xuất bởi Spring, nhưng tôi không thể tìm thấy tài liệu tham khảo để sao lưu.

Có một câu hỏi SO liên quan đã cố gắng đo lường hiệu suất và đi đến kết luận rằng "không có sự khác biệt".


nếu bạn không cung cấp setter getter trong thực thể thì việc sử dụng trường đó là gì ... bạn không thể sử dụng nó trong ứng dụng, các trường
becuase

1
Không phải là cung cấp một getter và setter cho các lĩnh vực của bạn thực tiễn xấu sao?, Tôi đoán nhận xét của tôi ở đây không phải lúc nào cũng đúng, vì tôi đã giả sử một lĩnh vực công cộng, trong khi đó rõ ràng có thể là một lĩnh vực riêng tư không bao giờ được truy cập.
Mathijs

3
@anshulkatta Tôi cảm thấy tôi thực sự nên giải quyết các câu hỏi của bạn, vì đó là tất cả những gì đóng gói. Lý tưởng nhất là tất cả các lĩnh vực của bạn nên ở chế độ riêng tư và nếu có thể thì chúng không nên có getters hoặc setters - đó là mức đóng gói tốt nhất mà bạn có thể hy vọng. Hãy xem xét một trình kiểm tra mật khẩu. Mật khẩu 2 trường riêngHash và failAttvor. Cả hai có thể là riêng tư mà không có getter hoặc setter. Chúng được sử dụng bởi bool checkPassword (mật khẩu chuỗi) băm, kiểm tra mật khẩuHash và sau đó cập nhật failAttvor và trả về kết quả. Không cần mã khác để truy cập hai trường đó.
Martin

2
@anshulkatta cần lưu ý rằng trong OOP, getters và setters là một mô hình chống, chúng đến từ lập trình thủ tục, có một lớp với chúng phá vỡ nguyên tắc đóng gói và tạo ra rất nhiều mã soạn sẵn, đó là cùng một loại mã lặp đi lặp lại nhiều lần. Các đối tượng nên là bất biến, nếu việc sửa đổi các thuộc tính của nó là bắt buộc thì nó phải được thực hiện thông qua phương thức làm một việc gì đó hơn là chỉ trả về giá trị của thuộc tính.
Uriel Arvizu

Không phải vậy. "Chống mẫu" trong trường hợp này là vấn đề quan điểm, không phải giáo điều. Với những gì đã nói, truy cập trường vẫn được ưa thích. Một ý tưởng tốt hơn là tránh xa các giải pháp ORM hoàn toàn. Tìm hiểu cách viết SQL thích hợp.
duffymo

38

Đây là một tình huống mà bạn phải sử dụng người truy cập tài sản. Hãy tưởng tượng bạn có một lớp trừu tượng CHUNG với nhiều điều tốt đẹp để thực hiện để kế thừa thành 8 lớp con cụ thể:

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
 }

Bây giờ chính xác làm thế nào bạn nên chú thích lớp này? Câu trả lời là BẠN KHÔNG THỂ chú thích nó với quyền truy cập trường hoặc thuộc tính vì bạn không thể chỉ định thực thể đích tại thời điểm này. Bạn phải chú thích các triển khai cụ thể. Nhưng vì các thuộc tính bền vững được khai báo trong siêu lớp này, bạn PHẢI sử dụng quyền truy cập thuộc tính trong các lớp con.

Truy cập trường không phải là một tùy chọn trong một ứng dụng với các siêu lớp chung chung trừu tượng.


2
chạm vào. Tôi đã không nghĩ về điều đó. Tôi đặt cược Hibernate đá ra một số sql điên cho những điều này.
Joseph Lust

8
Vấn đề này nghe có vẻ khó giải quyết về mặt cơ học mà không chú thích các thuộc tính, nhưng tôi chưa bao giờ gặp phải trường hợp tôi cần một lớp chung chung trừu tượng với nhiều cách thực hiện mà tôi cũng muốn tiếp tục. Thông thường tôi tạo một hệ thống phân cấp lớp để làm cho đối tượng của mình đa hình (làm cho nó trở thành loại phá vỡ chung), và không chỉ để tái sử dụng mã. Và "rất nhiều và rất nhiều triển khai" thường vi phạm SRP, trong trường hợp đó tôi có thể sẽ chuyển nó thành các lớp riêng biệt. Có một ví dụ cụ thể làm cho trường hợp sử dụng này rõ ràng hơn?
Merlyn Morgan-Graham

Ví dụ cụ thể duy nhất tôi có là ứng dụng của mình, mà tôi không thể mô tả trong một nhận xét 500 ký tự ;-)
HDave

3
Bạn có thể sử dụng abstract T getOneThing(), và abstract void setOneThing(T thing), và sử dụng truy cập trường.
Arturo Volpe

33

Tôi có xu hướng thích và sử dụng những người truy cập tài sản:

  • Tôi có thể thêm logic nếu có nhu cầu (như đã đề cập trong câu trả lời được chấp nhận).
  • nó cho phép tôi gọi foo.getId() mà không cần khởi tạo proxy (quan trọng khi sử dụng Hibernate, cho đến khi HHH-3718 được giải quyết).

Hạn chế:

  • nó làm cho mã ít đọc hơn, ví dụ bạn có thể duyệt cả một lớp để xem có @Transientxung quanh đó không.

nhưng sau đó nếu bạn sử dụng nhà cung cấp JPA không có "proxy" thì bạn không gặp phải vấn đề đó hay còn gọi là "nhà cung cấp JPA của bạn đang áp đặt lên bạn".
Neil Stockton

13

Điều đó thực sự phụ thuộc vào một trường hợp cụ thể - cả hai tùy chọn đều có sẵn vì một lý do. IMO nó sôi lên đến ba trường hợp:

  1. setter có một số logic không nên được thực thi tại thời điểm tải một thể hiện từ cơ sở dữ liệu; ví dụ: một số xác thực giá trị xảy ra trong setter, tuy nhiên dữ liệu đến từ db phải hợp lệ (nếu không nó sẽ không đến đó (:); trong trường hợp này, truy cập trường là phù hợp nhất;
  2. setter có một số logic phải luôn được gọi, ngay cả trong khi tải một cá thể từ db; ví dụ: tài sản đang được khởi tạo được sử dụng để tính toán một số trường được tính toán (ví dụ: tài sản - một số tiền, tài sản được tính toán - tổng cộng một số thuộc tính tiền tệ của cùng một ví dụ); trong trường hợp này truy cập tài sản là bắt buộc.
  3. Không có trường hợp nào ở trên - sau đó cả hai tùy chọn đều có thể áp dụng, chỉ cần nhất quán (ei nếu truy cập trường là lựa chọn trong tình huống này thì hãy sử dụng nó mọi lúc trong tình huống tương tự).

Tôi mới đến Hibernate và đấu tranh với cùng một câu hỏi. Tôi nghĩ rằng bài viết này cung cấp câu trả lời rõ ràng nhất. Cảm ơn bạn.
Sam Levin

12

Tôi đặc biệt khuyên bạn nên truy cập trường và KHÔNG chú thích trên getters (quyền truy cập thuộc tính) nếu bạn muốn làm bất cứ điều gì nhiều hơn trong setters thay vì chỉ đặt giá trị (ví dụ: Mã hóa hoặc tính toán).

Vấn đề với quyền truy cập thuộc tính là setters cũng được gọi khi đối tượng được tải. Điều này đã làm việc tốt với tôi trong nhiều tháng cho đến khi chúng tôi muốn giới thiệu mã hóa. Trong trường hợp sử dụng của chúng tôi, chúng tôi muốn mã hóa một trường trong setter và giải mã nó trong getter. Vấn đề bây giờ với quyền truy cập thuộc tính là khi Hibernate tải đối tượng, nó cũng đang gọi trình setter để điền vào trường và do đó đã mã hóa lại giá trị được mã hóa. Bài đăng này cũng đề cập đến điều này: Java Hibernate: Hành vi chức năng thiết lập thuộc tính khác nhau tùy thuộc vào người đang gọi nó

Điều này đã khiến tôi đau đầu cho đến khi tôi nhớ sự khác biệt giữa truy cập trường và quyền truy cập thuộc tính. Bây giờ tôi đã chuyển tất cả các chú thích của mình từ quyền truy cập thuộc tính sang quyền truy cập trường và hiện tại nó hoạt động tốt.


Có - Tôi đã thấy rằng nếu bạn sử dụng quyền truy cập thuộc tính, bạn thực sự không thể làm bất cứ điều gì trong trình thiết lập của mình ngoài việc đặt giá trị trường.
HDave

2
+1 Tránh xa getters / setters. Tôi sử dụng projectlombok.org và giữ chúng ẩn khỏi các nhà phát triển.
bhantol

11

Tôi thích sử dụng truy cập trường vì những lý do sau:

  1. Quyền truy cập thuộc tính có thể dẫn đến các lỗi rất khó chịu khi thực hiện bằng / hashCode và các trường tham chiếu trực tiếp (trái ngược với thông qua getters của chúng). Điều này là do proxy chỉ được khởi tạo khi truy cập getters và truy cập trường trực tiếp sẽ trả về null.

  2. Quyền truy cập thuộc tính yêu cầu bạn chú thích tất cả các phương thức tiện ích (ví dụ: addChild / removeChild) là @Transient.

  3. Với quyền truy cập trường, chúng ta có thể ẩn trường @Version bằng cách không hiển thị một getter nào cả. Một getter cũng có thể dẫn đến việc thêm một setter, và versiontrường không bao giờ được đặt thủ công (điều này có thể dẫn đến các vấn đề rất khó chịu). Tất cả gia tăng phiên bản phải được kích hoạt thông qua khóa rõ ràng OPTIMISTIC_FORCE_INCREMENT hoặc PESSIMISTIC_FORCE_INCREMENT .


1. Làm thế nào để chiến lược truy cập trường ngăn chặn điều này? Đây dường như là một cạm bẫy chung với các proxy, bất kể phong cách truy cập. 2. Bạn có chắc chắn, nó chỉ nên là getters tiện ích? (nhưng dù sao cũng là một lý lẽ tốt). 3. Hiển thị các bộ truy cập cho versiontrường thường hữu ích trong các tình huống sử dụng DTO thay vì các thực thể tách rời.
Dragan Bozanovic

1. Vì khi Proxy được khởi tạo. 2. Chắc chắn 100%. 3. Đó là một điểm hợp lệ.
Vlad Mihalcea

Xin tha thứ cho sự thiếu hiểu biết của tôi và có thể thiếu khả năng giải thích văn bản, (Tôi không phải là người nói tiếng Anh bản ngữ). Chỉ cần làm rõ, truy cập trường là khi không có phương thức getter / setter nào là đúng, vậy đối với POJO, được sử dụng toàn diện, các trường có công khai không? Nhưng bạn nói điều gì đó trong chủ đề đầu tiên và bài đăng trên blog được liên kết lại nói ngược lại. Điều tôi đã hiểu là bạn không thể sử dụng bằng khi sử dụng proxy và truy cập trường.
MaikoID

Không. Truy cập trường có nghĩa là Hibernate sử dụng các trường thông qua các phản xạ để đọc các thuộc tính thực thể. Để biết thêm chi tiết, hãy xem phần Loại truy cập trong Hướng dẫn sử dụng Hibernate .
Vlad Mihalcea

7

Tôi nghĩ rằng chú thích tài sản là tốt hơn bởi vì các trường cập nhật trực tiếp phá vỡ đóng gói, ngay cả khi ORM của bạn thực hiện nó.

Đây là một ví dụ tuyệt vời về nơi nó sẽ đốt cháy bạn: bạn có thể muốn các chú thích của mình cho trình xác nhận ngủ đông và sự kiên trì ở cùng một nơi (cả trường hoặc thuộc tính). Nếu bạn muốn kiểm tra các xác nhận hợp lệ của trình xác nhận ngủ đông được chú thích trên một trường, bạn không thể sử dụng một bản mô phỏng thực thể của mình để tách kiểm tra đơn vị của bạn thành chỉ trình xác nhận. Ôi.


2
Đó là lý do tại sao bạn đặt chú thích trình xác nhận cho người truy cập và chú thích liên tục trên các trường
xương cá

6

Tôi tin rằng truy cập tài sản so với truy cập trường là khác nhau tinh tế liên quan đến khởi tạo lười biếng.

Hãy xem xét các ánh xạ sau cho 2 loại đậu cơ bản:

<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>

Và các bài kiểm tra đơn vị sau:

@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();
}

Bạn sẽ thấy sự khác biệt tinh tế trong các lựa chọn cần thiết:

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

Đó là, gọi điện fb.getId()yêu cầu một lựa chọn, trong khi pb.getId()không.


Điều này thật buồn cười! :) Nhưng đó là một hành vi cụ thể thực hiện, tôi chắc chắn. Tôi
Vladimir Dyuzhev

Vâng, tôi đoán điều này là do thực tế là chỉ có các lớp liên tục được thiết bị. Tuy nhiên, thật đáng tiếc vì trường id thường là một trường không có giá trị kinh doanh và sẽ không cần bất kỳ người truy cập nào.
Maurice Perry

6

Hãy để tôi thử tóm tắt những lý do quan trọng nhất để chọn truy cập dựa trên trường. Nếu bạn muốn lặn sâu hơn, xin vui lòng đọc bài viết này trên blog của tôi: Chiến lược truy cập trong JPA và Hibernate - Cái nào tốt hơn, truy cập trường hoặc thuộc tính?

Truy cập dựa trên lĩnh vực cho đến nay là lựa chọn tốt hơn. Dưới đây là 5 lý do cho nó:

Lý do 1: Khả năng đọc mã của bạn tốt hơn

Nếu bạn sử dụng quyền truy cập dựa trên trường, bạn chú thích các thuộc tính thực thể với các chú thích ánh xạ của bạn. Bằng cách đặt định nghĩa của tất cả các thuộc tính thực thể ở đầu lớp, bạn sẽ có được cái nhìn tương đối nhỏ gọn về tất cả các thuộc tính và ánh xạ của chúng.

Lý do 2: Bỏ qua các phương thức getter hoặc setter mà ứng dụng của bạn không nên gọi

Một ưu điểm khác của truy cập dựa trên trường là nhà cung cấp kiên trì của bạn, ví dụ, Hibernate hoặc EclipseLink, không sử dụng các phương thức getter và setter của các thuộc tính thực thể của bạn. Điều đó có nghĩa là bạn không cần cung cấp bất kỳ phương thức nào không được sử dụng bởi mã doanh nghiệp của bạn. Đây thường là trường hợp cho các phương thức setter của các thuộc tính khóa chính hoặc các cột phiên bản được tạo. Nhà cung cấp kiên trì của bạn quản lý các giá trị của các thuộc tính này và bạn không nên đặt chúng theo chương trình.

Lý do 3: Triển khai linh hoạt các phương thức getter và setter

Vì nhà cung cấp kiên trì của bạn không gọi các phương thức getter và setter, nên họ không bị buộc phải thực hiện bất kỳ yêu cầu bên ngoài nào. Bạn có thể thực hiện các phương pháp này theo bất kỳ cách nào bạn muốn. Điều đó cho phép bạn thực hiện các quy tắc xác thực dành riêng cho doanh nghiệp, để kích hoạt logic nghiệp vụ bổ sung hoặc chuyển đổi thuộc tính thực thể thành một loại dữ liệu khác.

Ví dụ, bạn có thể sử dụng điều đó để bọc một liên kết hoặc thuộc tính tùy chọn vào Java Optional.

Lý do 4: Không cần đánh dấu các phương thức tiện ích như @Transient

Một lợi ích khác của chiến lược truy cập dựa trên trường là bạn không cần chú thích các phương thức tiện ích của mình @Transient. Chú thích này cho nhà cung cấp kiên trì của bạn rằng một phương thức hoặc thuộc tính không phải là một phần của trạng thái bền vững thực thể. Và bởi vì với quyền truy cập kiểu trường, trạng thái liên tục được xác định bởi các thuộc tính của thực thể của bạn, việc triển khai JPA của bạn bỏ qua tất cả các phương thức của thực thể.

Lý do 5: Tránh lỗi khi làm việc với proxy

Hibernate sử dụng proxy cho các hiệp hội được tìm nạp một cách lười biếng để nó có thể kiểm soát việc khởi tạo các hiệp hội này. Cách tiếp cận đó hoạt động tốt trong hầu hết các tình huống. Nhưng nó giới thiệu một cạm bẫy nguy hiểm nếu bạn sử dụng quyền truy cập dựa trên tài sản.

Nếu bạn sử dụng quyền truy cập dựa trên thuộc tính, Hibernate sẽ khởi tạo các thuộc tính của đối tượng proxy khi bạn gọi phương thức getter. Đó luôn là trường hợp nếu bạn sử dụng đối tượng proxy trong mã doanh nghiệp của mình. Nhưng khá nhiều triển khai bằng và hashCode truy cập trực tiếp vào các thuộc tính. Nếu đây là lần đầu tiên bạn truy cập bất kỳ thuộc tính proxy nào, các thuộc tính này vẫn chưa được khởi tạo.


3

Theo mặc định, các nhà cung cấp JPA truy cập các giá trị của các trường thực thể và ánh xạ các trường đó vào các cột cơ sở dữ liệu bằng cách sử dụng các phương thức truy cập thuộc tính Java (getter) và trình biến đổi (setter) của thực thể. Như vậy, tên và loại của các trường riêng trong một thực thể không quan trọng đối với JPA. Thay vào đó, JPA chỉ xem xét các tên và kiểu trả về của các bộ truy cập thuộc tính JavaBean. Bạn có thể thay đổi điều này bằng cách sử dụng @javax.persistence.Accesschú thích, cho phép bạn chỉ định rõ ràng phương pháp truy cập mà nhà cung cấp JPA nên sử dụng.

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

Các tùy chọn khả dụng cho enum AccessType là PROPERTY (mặc định) và FIELD. Với SỞ HỮU, nhà cung cấp nhận và đặt các giá trị trường bằng các phương thức thuộc tính JavaBean. FIELD làm cho nhà cung cấp nhận và đặt giá trị trường bằng cách sử dụng các trường đối tượng. Như một cách thực hành tốt nhất, bạn chỉ nên bám vào mặc định và sử dụng các thuộc tính JavaBean trừ khi bạn có lý do thuyết phục để làm khác.

Bạn có thể đặt các chú thích thuộc tính này trên các trường riêng hoặc các phương thức truy cập công khai. Nếu bạn sử dụng AccessType.PROPERTY(mặc định) và chú thích các trường riêng thay vì các bộ truy cập JavaBean, tên trường phải khớp với tên thuộc tính JavaBean. Tuy nhiên, tên không phải khớp nếu bạn chú thích các bộ truy cập JavaBean. Tương tự, nếu bạn sử dụng AccessType.FIELDvà chú thích các bộ truy cập JavaBean thay vì các trường, tên trường cũng phải khớp với tên thuộc tính JavaBean. Trong trường hợp này, chúng không phải khớp nếu bạn chú thích các trường. Tốt nhất là chỉ nhất quán và chú thích các trình truy cập JavaBean cho AccessType.PROPERTYvà các trường cho AccessType.FIELD.

Điều quan trọng là bạn không bao giờ nên trộn lẫn các chú thích thuộc tính JPA và chú thích trường JPA trong cùng một thực thể. Làm như vậy dẫn đến hành vi không xác định và rất có thể gây ra lỗi.


2

Chúng ta đã ở đó chưa

Đó là một bản trình bày cũ nhưng Rod gợi ý rằng chú thích về quyền truy cập thuộc tính khuyến khích các mô hình miền thiếu máu và không nên là cách "mặc định" để chú thích.


2

Một điểm khác có lợi cho truy cập trường là nếu không, bạn buộc phải phơi bày setters cho các bộ sưu tập, đối với tôi, đó là một ý tưởng tồi khi thay đổi thể hiện bộ sưu tập liên tục thành một đối tượng không được quản lý bởi Hibernate chắc chắn sẽ phá vỡ tính nhất quán dữ liệu của bạn.

Vì vậy, tôi thích có các bộ sưu tập như các trường được bảo vệ khởi tạo thành các triển khai trống trong hàm tạo mặc định và chỉ hiển thị các biểu đồ của chúng. Hoạt động sau đó, chỉ được quản lý như clear(), remove(), removeAll()vv đều có thể sẽ không bao giờ làm cho Hibernate không biết gì về sự thay đổi.


Bạn không bị buộc phải phơi bày bất cứ điều gì vì setters có thể được bảo vệ. Ngoài ra, các setters không phải là một phần của giao diện đang được triển khai nên ngay cả khi chúng là công khai, chúng không dễ truy cập.
HDave

2

Tôi thích các lĩnh vực, nhưng tôi đã gặp phải một tình huống dường như buộc tôi phải đặt các chú thích trên getters.

Với việc triển khai JPA Hibernate, @Embeddeddường như không hoạt động trên các trường. Vì vậy, phải đi trên getter. Và một khi bạn đặt nó trên getter, thì các @Columnchú thích khác nhau cũng phải đi trên các getters. (Tôi nghĩ rằng Hibernate không muốn trộn các trường và getters ở đây.) Và một khi bạn đã đặt các @Columngetters trong một lớp, có lẽ sẽ có ý nghĩa khi làm điều đó xuyên suốt.


2

Tôi ủng hộ người truy cập trường. Mã sạch hơn nhiều. Tất cả các chú thích có thể được đặt trong một phần của một lớp và mã dễ đọc hơn nhiều.

Tôi đã tìm thấy một vấn đề khác với người truy cập thuộc tính: nếu bạn có các phương thức getXYZ trên lớp của bạn KHÔNG được chú thích là có liên quan đến các thuộc tính liên tục, hibernate tạo sql để cố lấy các thuộc tính đó, dẫn đến một số thông báo lỗi rất khó hiểu. Hai giờ lãng phí. Tôi đã không viết mã này; Tôi đã luôn sử dụng các bộ truy cập trường trong quá khứ và chưa bao giờ gặp phải vấn đề này.

Phiên bản ngủ đông được sử dụng trong ứng dụng này:

<!-- 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>

2

Bạn nên chọn truy cập thông qua các trường trên truy cập thông qua các thuộc tính. Với các trường bạn có thể giới hạn dữ liệu gửi và nhận. Với thông qua các thuộc tính, bạn có thể gửi thêm dữ liệu dưới dạng máy chủ lưu trữ và đặt các mệnh giá G (nhà máy này đặt hầu hết các thuộc tính trong tổng số).




1

Chúng tôi đã tạo các thực thể và sử dụng các chú thích getter. Vấn đề chúng tôi gặp phải là đây: một số thực thể có các quy tắc phức tạp đối với một số thuộc tính liên quan đến thời điểm chúng có thể được cập nhật. Giải pháp là có một số logic nghiệp vụ trong mỗi setter xác định xem giá trị thực có thay đổi hay không và nếu có thì có nên cho phép thay đổi hay không. Tất nhiên, Hibernate luôn có thể đặt các thuộc tính, vì vậy chúng tôi đã kết thúc với hai nhóm setters. Khá xấu xí.

Đọc các bài viết trước, tôi cũng thấy rằng việc tham chiếu các thuộc tính từ bên trong thực thể có thể dẫn đến các vấn đề với các bộ sưu tập không tải.

Tóm lại, tôi sẽ nghiêng về chú thích các lĩnh vực trong tương lai.


0

Thông thường đậu là POJO, vì vậy dù sao họ cũng có người truy cập.

Vì vậy, câu hỏi không phải là "cái nào tốt hơn?", Mà đơn giản là "khi nào nên sử dụng truy cập trường?". Và câu trả lời là "khi bạn không cần setter / getter cho trường!".


4
Vấn đề là bạn không thể trộn lẫn quyền truy cập trường và quyền truy cập thuộc tính trong POJO - bạn phải chọn một
Martin OConnor

Có thật không? Tôi đã quên nó. Dù sao, tôi luôn sử dụng POJO một người truy cập d.
Vladimir Dyuzhev

Lưu ý rằng với JPA 2.0 (không xuất hiện khi câu hỏi này được hỏi), giờ đây bạn có thể trộn các loại truy cập bằng cách sử dụng chú thích @AccessType.
mtpettyp

0

tôi nghĩ về điều này và tôi chọn phương pháp accesor

tại sao?

bởi vì accesor của trường và methos là như nhau nhưng nếu sau này tôi cần một số logic trong trường tải, tôi lưu di chuyển tất cả các chú thích được đặt trong các trường

Trân trọng

Grubhart


0

Để làm cho các lớp của bạn sạch hơn, hãy đặt chú thích vào trường sau đó sử dụng @Access (AccessType.PROPERTY)



0

AccessType.PROPERTY: Việc triển khai kiên trì EJB sẽ tải trạng thái vào lớp của bạn thông qua các phương thức "setter" của JavaBean và lấy trạng thái từ lớp của bạn bằng các phương thức "getter" của JavaBean. Đây là mặc định.

AccessType.FIELD: Trạng thái được tải và truy xuất trực tiếp từ các trường của lớp bạn. Bạn không phải viết "getters" và "setters" của JavaBean.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.