This question is somewhat related to Hibernate Annotation Placement Question.
这个问题与Hibernate注释放置问题有关。
But I want to know which is better? Access via properties or access via fields? What are the advantages and disadvantages of each?
但我想知道哪种更好?通过属性访问或通过字段访问?它们的优缺点是什么?
21 个解决方案
#1
28
I prefer accessors, since I can add some business logic to my accessors whenever I need. Here's an example:
我更喜欢访问器,因为只要我需要,我可以向访问器添加一些业务逻辑。这里有一个例子:
@Entity
public class Person {
@Column("nickName")
public String getNickName(){
if(this.name != null) return generateFunnyNick(this.name);
else return "John Doe";
}
}
Besides, if you throw another libs into the mix (like some JSON-converting lib or BeanMapper or Dozer or other bean mapping/cloning lib based on getter/setter properties) you'll have the guarantee that the lib is in sync with the persistence manager (both use the getter/setter).
此外,如果您将另一个libs放入混合(如一些json -convert lib或BeanMapper或Dozer或其他基于getter/setter属性的bean映射/克隆库),您将保证lib与持久性管理器(都使用getter/setter)同步。
#2
215
There are arguments for both, but most of them stem from certain user requirements "what if you need to add logic for", or "xxxx breaks encapsulation". However, nobody has really commented on the theory, and given a properly reasoned argument.
这两种说法都有争议,但大多数都源自特定的用户需求“如果您需要为”或“xxxx中断封装”添加逻辑。然而,没有人真正评论过这个理论,并给出了一个合理的论证。
What is Hibernate/JPA actually doing when it persists an object - well, it is persisting the STATE of the object. That means storing it in a way that it can be easily reproduced.
当Hibernate/JPA保存一个对象时,它实际上在做什么?这意味着要以一种易于复制的方式来存储它。
What is encapsulation? Encapsulations means encapsulating the data (or state) with an interface that the application/client can use to access the data safely - keeping it consistent and valid.
封装是什么?封装意味着将数据(或状态)封装到一个接口中,应用程序/客户端可以使用这个接口安全地访问数据——保持它的一致性和有效性。
Think of this like MS Word. MS Word maintains a model of the document in memory - the documents STATE. It presents an interface that the user can use to modify the document - a set of buttons, tools, keyboard commands etc. However, when you choose to persist (Save) that document, it saves the internal state, not the set of keypresses and mouse clicks used to generate it.
想想这个词吧。MS Word在内存中维护文档的模型——文档状态。它提供了一个用户可以用来修改文档的界面——一组按钮、工具、键盘命令等等。但是,当你选择保存文档时,它保存了内部状态,而不是用来生成它的按键和鼠标点击的集合。
Saving the internal state of the object DOES NOT break encapsulation - otherwise you don't really understand what encapsulation means, and why it exists. It is just like object serialisation really.
保存对象的内部状态不会破坏封装——否则您不会真正理解封装的含义以及它存在的原因。这就像对象序列化一样。
For this reason, IN MOST CASES, it is appropriate to persist the FIELDS and not the ACCESSORS. This means that an object can be accurately recreated from the database exactly the way it was stored. It should not need any validation, because this was done on the original when it was created, and before it was stored in the database (unless, God forbid, you are storing invalid data in the DB!!!!). Likewise, there should be no need to calculate values, as they were already calculated before the object was stored. The object should look just the way it did before it was saved. In fact, by adding additional stuff into the getters/setters you are actually increasing the risk that you will recreate something that is not an exact copy of the original.
出于这个原因,在大多数情况下,应该持久化字段而不是访问器。这意味着可以从数据库中精确地重新创建对象,其方式与存储对象的方式完全相同。它不应该需要任何验证,因为这是在创建它时在原始数据上完成的,并且在它存储到数据库之前(除非,上帝不允许,您正在数据库中存储无效数据!!!)同样,不需要计算值,因为在存储对象之前已经计算了值。对象应该与保存之前的方法相同。实际上,通过在getter /setter中添加额外的东西,实际上增加了您将重新创建一个不完全副本的风险。
Of course, this functionality was added for a reason. There may be some valid use cases for persisting the accessors, however, they will typically be rare. An example may be that you want to avoid persisting a calculated value, though you may want to ask the question why you don't calculate it on demand in the value's getter, or lazily initialise it in the getter. Personally I cannot think of any good use case, and none of the answers here really give a "Software Engineering" answer.
当然,添加这个功能是有原因的。可能有一些有效的用于持久化访问器的用例,但是,它们通常很少。例如,您可能想要避免持久化计算值,但是您可能想问一下为什么不按值的getter方法计算它,或者在getter中惰性地初始化它。就我个人而言,我想不出任何好的用例,这里的任何答案都不能真正给出“软件工程”的答案。
#3
73
I prefer field access, because that way I'm not forced to provide getter/setter for each property.
我更喜欢字段访问,因为这样我就不必为每个属性提供getter/setter了。
A quick survey via Google suggests that field access is the majority (e.g., http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype).
通过谷歌进行的一项快速调查表明,字段访问最多(例如http://java.dzone.com/tips/12-feb-jpa-20 why-accesstype)。
I believe field access is the idiom recommended by Spring, but I can't find a reference to back that up.
我相信field access是Spring推荐的习惯用法,但是我找不到一个引用来支持它。
There's a related SO question that tried to measure performance and came to the conclusion that there's "no difference".
有一个相关的问题,试图衡量绩效,并得出结论,“没有区别”。
#4
35
Here's a situation where you HAVE to use property accessors. Imagine you have a GENERIC abstract class with lots of implementation goodness to inherit into 8 concrete subclasses:
这里需要使用属性访问器。假设您有一个泛型抽象类,它具有很多实现优点,可以继承到8个具体的子类中:
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
}
Now exactly how should you annotate this class? The answer is YOU CAN'T annotate it at all with either field or property access because you can't specify the target entity at this point. You HAVE to annotate the concrete implementations. But since the persisted properties are declared in this superclass, you MUST used property access in the subclasses.
现在,你该如何注释这个类呢?答案是你不能用字段或属性访问来注释它,因为你现在不能指定目标实体。您必须注释具体的实现。但是由于持久化属性是在这个超类中声明的,所以必须在子类中使用属性访问。
Field access is not an option in an application with abstract generic super-classes.
在具有抽象泛型超类的应用程序中,字段访问不是一个选项。
#5
33
I tend to prefer and to use property accessors:
我倾向于使用属性访问器:
- I can add logic if the need arises (as mentioned in the accepted answer).
- 如果需要,我可以添加逻辑(如所接受的答案中所提到的)。
- it allows me to call
foo.getId()
without initializing a proxy (important when using Hibernate, until HHH-3718 get resolved). - 它允许我在不初始化代理(在使用Hibernate时很重要,直到HHH-3718得到解决)的情况下调用foo.getId()。
Drawback:
缺点:
- it makes the code less readable, you have for example to browse a whole class to see if there are
@Transient
around there. - 它使代码可读性降低,例如,您必须浏览整个类,以查看是否有@Transient。
#6
13
That really depends on a specific case -- both options are available for a reason. IMO it boils down to three cases:
这取决于具体情况——这两种选择都是有原因的。在我看来,可以归结为三种情况:
- setter has some logic that should not be executed at the time of loading an instance from a database; for example, some value validation happens in the setter, however the data coming from db should be valid (otherwise it would not get there (: ); in this case field access is most appropriate;
- setter具有在从数据库加载实例时不应执行的某些逻辑;例如,一些值验证发生在setter中,但是来自db的数据应该是有效的(否则它不会到达那里(:);在这种情况下,字段访问是最合适的;
- setter has some logic that should always be invoked, even during loading of an instance from db; for example, the property being initialised is used in computation of some calculated field (e.g. property -- a monetary amount, calculated property -- a total of several monetary properties of the same instance); in this case property access is required.
- setter有一些逻辑应该始终被调用,即使是在从db加载实例时;例如,被初始化的属性用于计算某些计算字段(例如,属性——货币数量、计算属性——同一实例的若干货币属性的总和);在这种情况下,需要属性访问。
- None of the above cases -- then both options are applicable, just stay consistent (e.i. if field access is the choice in this situation then use it all the time in similar situation).
- 上述情况都不存在——那么这两个选项都是适用的,只要保持一致(例如,如果在这种情况下选择字段访问,那么在类似的情况下始终使用字段访问)。
#7
12
I would strongly recommend field access and NOT annotations on the getters (property access) if you want to do anything more in the setters than just setting the value (e.g. Encryption or calculation).
如果您想在setter中做更多的事情,而不只是设置值(例如加密或计算),那么我强烈推荐字段访问,而不是getters(属性访问)上的注释。
The problem with the property access is that the setters are also called when the object is loaded. This has worked for me fine for many month until we wanted to introduce encryption. In our use case we wanted to encrypt a field in the setter and decrypt it in the getter. The problem now with property access was that when Hibernate loaded the object it was also calling the setter to populate the field and thus was encrypting the encrypted value again. This post also mentions this: Java Hibernate: Different property set function behavior depending on who is calling it
属性访问的问题是,在加载对象时还调用setter。在引入加密之前,这对我来说已经有好几个月了。在我们的用例中,我们希望加密setter中的字段并在getter中解密它。属性访问现在的问题是,当Hibernate加载对象时,它还调用setter来填充字段,从而再次加密加密加密的值。这篇文章还提到:Java Hibernate:不同的属性集函数行为取决于调用它的人
This has cause me headaches until I remembered the difference between field access and property access. Now I have moved all my annotations from property access to field access and it works fine now.
这让我头疼,直到我想起字段访问和属性访问之间的区别。现在,我已经将所有注释从属性访问移动到字段访问,现在它可以正常工作了。
#8
7
I think annotating the property is better because updating fields directly breaks encapsulation, even when your ORM does it.
我认为对属性进行注释更好,因为更新字段会直接破坏封装,即使您的ORM完成了它。
Here's a great example of where it will burn you: you probably want your annotations for hibernate validator & persistence in the same place (either fields or properties). If you want to test your hibernate validator powered validations which are annotated on a field, you can't use a mock of your entity to isolate your unit test to just the validator. Ouch.
这里有一个很好的例子,说明它将在哪里烧坏您:您可能希望hibernate validator & persistence的注释位于相同的位置(字段或属性)。如果您想测试您的hibernate验证器支持的验证,这些验证被注释在一个字段中,您不能使用实体的模拟来将单元测试隔离为验证器。哎哟。
#9
6
I believe property access vs. field access is subtly different with regards to lazy initialisation.
我认为属性访问和字段访问在延迟初始化方面有着微妙的不同。
Consider the following mappings for 2 basic beans:
考虑以下两个基本bean的映射:
<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>
And the following unit tests:
及以下单元测试:
@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();
}
You will see the subtle difference in the selects required:
您将看到所需选择的细微差别:
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
That is, calling fb.getId()
requires a select, whereas pb.getId()
does not.
也就是说,调用fb.getId()需要选择,而pb.getId()则不需要。
#10
5
I prefer using field access for the following reasons:
我喜欢使用字段访问,原因如下:
-
The property access can lead to very nasty bugs when implementing equals/hashCode and referencing fields directly (as opposed through their getters). This is because the proxy is only initialized when the getters are accessed, and a direct-field access would simply return null.
当实现equals/hashCode并直接引用字段(而不是通过它们的getter)时,属性访问会导致非常讨厌的bug。这是因为只有在访问getter时才初始化代理,而直接字段访问只会返回null。
-
The property access requires you to annotate all utility methods (e.g. addChild/removeChild) as
@Transient
.属性访问要求您将所有实用方法(例如addChild/removeChild)注释为@Transient。
-
With field access we can hide the @Version field by not exposing a getter at all. A getter can also lead to adding a setter as well, and the
version
field should never be set manually (which can lead to very nasty issues). All version incrementation should be triggered through OPTIMISTIC_FORCE_INCREMENT or PESSIMISTIC_FORCE_INCREMENT explicit locking.通过字段访问,我们可以隐藏@Version字段,而不需要公开getter。getter也可能导致添加setter,而且不应该手动设置版本字段(这会导致非常棘手的问题)。所有版本增量都应该通过OPTIMISTIC_FORCE_INCREMENT或invalimistic_force_increment显式锁定来触发。
#11
2
我们在那了吗
That's an old presentation but Rod suggests that annotation on property access encourages anemic domain models and should not be the "default" way to annotate.
这是一个旧的表示,但Rod建议属性访问的注释鼓励了贫血的域模型,不应该是“默认”的注释方式。
#12
2
Another point in favor of field access is that otherwise you are forced to expose setters for collections as well what, for me, is a bad idea as changing the persistent collection instance to an object not managed by Hibernate will definitely break your data consistency.
另一个支持字段访问的观点是,否则您将*为集合公开setter,对我来说,将持久集合实例更改为非Hibernate管理的对象肯定会破坏数据一致性,这对我来说是一个坏主意。
So I prefer having collections as protected fields initialized to empty implementations in the default constructor and expose only their getters. Then, only managed operations like clear()
, remove()
, removeAll()
etc are possible that will never make Hibernate unaware of changes.
因此,我更喜欢在默认构造函数中将集合作为受保护字段初始化为空实现,并只公开它们的getter。然后,只有像clear()、remove()、removeAll()等托管操作才有可能使Hibernate不知道更改。
#13
2
I prefer fields, but I've run into one situation that seems to force me to place the annotations on getters.
我更喜欢字段,但我遇到了一种情况,似乎迫使我将注释放在getter上。
With the Hibernate JPA implementation, @Embedded
doesn't seem to work on fields. So that has to go on the getter. And once you put that on the getter, then the various @Column
annotations have to go on the getters too. (I think Hibernate doesn't want mixing fields and getters here.) And once you're putting @Column
on getters in one class, it probably makes sense to do that throughout.
使用Hibernate JPA实现,@嵌入式似乎不能在字段上工作。所以它必须在getter上。一旦你把它放在getter上,那么各种@Column注释也必须放在getter上。(我认为Hibernate不希望在这里混合字段和getter。)一旦你把@Column放在一个类中,那么在整个类中这样做是有意义的。
#14
2
I favor field accessors. The code is much cleaner. All the annotations can be placed in one section of a class and the code is much easier to read.
我喜欢字段访问器。代码要干净得多。所有注释都可以放在类的一个部分中,代码更容易阅读。
I found another problem with property accessors: if you have getXYZ methods on your class that are NOT annotated as being associated with persistent properties, hibernate generates sql to attempt to get those properties, resulting in some very confusing error messages. Two hours wasted. I did not write this code; I have always used field accessors in the past and have never run into this issue.
我发现了属性访问器的另一个问题:如果您的类上有getXYZ方法,但没有注释为与持久属性相关联,那么hibernate会生成sql来尝试获取这些属性,从而导致一些非常混乱的错误消息。浪费了两个小时。我没有写这段代码;我过去一直使用字段访问器,从来没有遇到过这个问题。
Hibernate versions used in this app:
本应用使用的Hibernate版本:
<!-- 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>
#15
1
I had the same question regarding accesstype in hibernate and found some answers here.
我对冬眠中的accesstype也有同样的问题,在这里我找到了一些答案。
#16
1
I have solved lazy initialisation and field access here Hibernate one-to-one: getId() without fetching entire object
我在这里解决了延迟初始化和字段访问Hibernate一对一:getId(),而不获取整个对象
#17
1
We created entity beans and used getter annotations. The problem we ran into is this: some entities have complex rules for some properties regarding when they can be updated. The solution was to have some business logic in each setter that determines whether or not the actual value changed and, if so, whether the change should be allowed. Of course, Hibernate can always set the properties, so we ended up with two groups of setters. Pretty ugly.
我们创建了实体bean并使用了getter注释。我们遇到的问题是:一些实体对于某些属性有关于何时可以更新的复杂规则。解决方案是在每个setter中都包含一些业务逻辑,以确定实际值是否更改,如果更改,是否应该允许更改。当然,Hibernate总是可以设置属性,所以我们最后得到了两组setter。很丑。
Reading previous posts, I also see that referencing the properties from inside the entity could lead to issues with collections not loading.
在阅读之前的文章时,我还发现从实体内部引用属性可能会导致集合不加载的问题。
Bottom line, I would lean toward annotating the fields in the future.
总之,我倾向于在将来注释这些字段。
#18
1
By default, JPA providers access the values of entity fields and map those fields to database columns using the entity’s JavaBean property accessor (getter) and mutator (setter) methods. As such, the names and types of the private fields in an entity do not matter to JPA. Instead, JPA looks at only the names and return types of the JavaBean property accessors. You can alter this using the @javax.persistence.Access
annotation, which enables you to explicitly specify the access methodology that the JPA provider should employ.
默认情况下,JPA提供程序访问实体字段的值,并使用实体的JavaBean属性访问器(getter)和mutator (setter)方法将这些字段映射到数据库列。因此,实体中的私有字段的名称和类型对JPA并不重要。相反,JPA只查看JavaBean属性访问器的名称和返回类型。您可以使用@javax.persistence更改它。Access annotation,它允许您显式地指定JPA提供者应该使用的访问方法。
@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}
The available options for the AccessType enum are PROPERTY (the default) and FIELD. With PROPERTY, the provider gets and sets field values using the JavaBean property methods. FIELD makes the provider get and set field values using the instance fields. As a best practice, you should just stick to the default and use JavaBean properties unless you have a compelling reason to do otherwise.
AccessType enum的可用选项是属性(默认)和字段。对于属性,提供者使用JavaBean属性方法获取和设置字段值。字段使提供程序获取并使用实例字段设置字段值。作为一种最佳实践,您应该坚持使用默认属性并使用JavaBean属性,除非您有令人信服的理由不这么做。
You can put these property annotations on either the private fields or the public accessor methods. If you use AccessType.PROPERTY
(default) and annotate the private fields instead of the JavaBean accessors, the field names must match the JavaBean property names. However, the names do not have to match if you annotate the JavaBean accessors. Likewise, if you use AccessType.FIELD
and annotate the JavaBean accessors instead of the fields, the field names must also match the JavaBean property names. In this case, they do not have to match if you annotate the fields. It’s best to just be consistent and annotate the JavaBean accessors for AccessType.PROPERTY
and the fields for AccessType.FIELD
.
您可以将这些属性注释放在私有字段或公共访问器方法上。如果你使用AccessType。属性(默认)并注释私有字段而不是JavaBean访问器,字段名必须与JavaBean属性名匹配。但是,如果您注释了JavaBean访问器,则不必匹配名称。同样,如果你使用AccessType。字段并注释JavaBean访问器而不是字段,字段名也必须与JavaBean属性名匹配。在这种情况下,如果您对字段进行注释,它们就不需要匹配。最好保持一致并为AccessType注释JavaBean访问器。属性和用于AccessType.FIELD的字段。
It is important that you should never mix JPA property annotations and JPA field annotations in the same entity. Doing so results in unspecified behavior and is very likely to cause errors.
重要的是,您不应该在同一个实体中混合JPA属性注释和JPA字段注释。这样做会导致未指定的行为,并且很可能导致错误。
#19
0
Normally beans are POJO, so they have accessors anyway.
通常情况下,bean是POJO,所以它们有访问器。
So the question is not "which one is better?", but simply "when to use field access?". And the answer is "when you don't need a setter/getter for the field!".
所以问题不是“哪个更好?”,而只是“何时使用字段访问?”答案是“当你不需要一个setter/getter时!”
#20
0
i thinking about this and i choose method accesor
我考虑了一下,选择了方法accesor
why?
为什么?
because field and methos accesor is the same but if later i need some logic in load field, i save move all annotation placed in fields
因为field和methos accesor是相同的,但是如果以后我需要在load字段中使用一些逻辑,我就保存放在字段中的move all annotation
regards
问候
Grubhart
Grubhart
#21
0
To make your classes cleaner, put the annotation in the field then use @Access(AccessType.PROPERTY)
要使类更清晰,请将注释放在字段中,然后使用@Access(AccessType.PROPERTY)
#1
28
I prefer accessors, since I can add some business logic to my accessors whenever I need. Here's an example:
我更喜欢访问器,因为只要我需要,我可以向访问器添加一些业务逻辑。这里有一个例子:
@Entity
public class Person {
@Column("nickName")
public String getNickName(){
if(this.name != null) return generateFunnyNick(this.name);
else return "John Doe";
}
}
Besides, if you throw another libs into the mix (like some JSON-converting lib or BeanMapper or Dozer or other bean mapping/cloning lib based on getter/setter properties) you'll have the guarantee that the lib is in sync with the persistence manager (both use the getter/setter).
此外,如果您将另一个libs放入混合(如一些json -convert lib或BeanMapper或Dozer或其他基于getter/setter属性的bean映射/克隆库),您将保证lib与持久性管理器(都使用getter/setter)同步。
#2
215
There are arguments for both, but most of them stem from certain user requirements "what if you need to add logic for", or "xxxx breaks encapsulation". However, nobody has really commented on the theory, and given a properly reasoned argument.
这两种说法都有争议,但大多数都源自特定的用户需求“如果您需要为”或“xxxx中断封装”添加逻辑。然而,没有人真正评论过这个理论,并给出了一个合理的论证。
What is Hibernate/JPA actually doing when it persists an object - well, it is persisting the STATE of the object. That means storing it in a way that it can be easily reproduced.
当Hibernate/JPA保存一个对象时,它实际上在做什么?这意味着要以一种易于复制的方式来存储它。
What is encapsulation? Encapsulations means encapsulating the data (or state) with an interface that the application/client can use to access the data safely - keeping it consistent and valid.
封装是什么?封装意味着将数据(或状态)封装到一个接口中,应用程序/客户端可以使用这个接口安全地访问数据——保持它的一致性和有效性。
Think of this like MS Word. MS Word maintains a model of the document in memory - the documents STATE. It presents an interface that the user can use to modify the document - a set of buttons, tools, keyboard commands etc. However, when you choose to persist (Save) that document, it saves the internal state, not the set of keypresses and mouse clicks used to generate it.
想想这个词吧。MS Word在内存中维护文档的模型——文档状态。它提供了一个用户可以用来修改文档的界面——一组按钮、工具、键盘命令等等。但是,当你选择保存文档时,它保存了内部状态,而不是用来生成它的按键和鼠标点击的集合。
Saving the internal state of the object DOES NOT break encapsulation - otherwise you don't really understand what encapsulation means, and why it exists. It is just like object serialisation really.
保存对象的内部状态不会破坏封装——否则您不会真正理解封装的含义以及它存在的原因。这就像对象序列化一样。
For this reason, IN MOST CASES, it is appropriate to persist the FIELDS and not the ACCESSORS. This means that an object can be accurately recreated from the database exactly the way it was stored. It should not need any validation, because this was done on the original when it was created, and before it was stored in the database (unless, God forbid, you are storing invalid data in the DB!!!!). Likewise, there should be no need to calculate values, as they were already calculated before the object was stored. The object should look just the way it did before it was saved. In fact, by adding additional stuff into the getters/setters you are actually increasing the risk that you will recreate something that is not an exact copy of the original.
出于这个原因,在大多数情况下,应该持久化字段而不是访问器。这意味着可以从数据库中精确地重新创建对象,其方式与存储对象的方式完全相同。它不应该需要任何验证,因为这是在创建它时在原始数据上完成的,并且在它存储到数据库之前(除非,上帝不允许,您正在数据库中存储无效数据!!!)同样,不需要计算值,因为在存储对象之前已经计算了值。对象应该与保存之前的方法相同。实际上,通过在getter /setter中添加额外的东西,实际上增加了您将重新创建一个不完全副本的风险。
Of course, this functionality was added for a reason. There may be some valid use cases for persisting the accessors, however, they will typically be rare. An example may be that you want to avoid persisting a calculated value, though you may want to ask the question why you don't calculate it on demand in the value's getter, or lazily initialise it in the getter. Personally I cannot think of any good use case, and none of the answers here really give a "Software Engineering" answer.
当然,添加这个功能是有原因的。可能有一些有效的用于持久化访问器的用例,但是,它们通常很少。例如,您可能想要避免持久化计算值,但是您可能想问一下为什么不按值的getter方法计算它,或者在getter中惰性地初始化它。就我个人而言,我想不出任何好的用例,这里的任何答案都不能真正给出“软件工程”的答案。
#3
73
I prefer field access, because that way I'm not forced to provide getter/setter for each property.
我更喜欢字段访问,因为这样我就不必为每个属性提供getter/setter了。
A quick survey via Google suggests that field access is the majority (e.g., http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype).
通过谷歌进行的一项快速调查表明,字段访问最多(例如http://java.dzone.com/tips/12-feb-jpa-20 why-accesstype)。
I believe field access is the idiom recommended by Spring, but I can't find a reference to back that up.
我相信field access是Spring推荐的习惯用法,但是我找不到一个引用来支持它。
There's a related SO question that tried to measure performance and came to the conclusion that there's "no difference".
有一个相关的问题,试图衡量绩效,并得出结论,“没有区别”。
#4
35
Here's a situation where you HAVE to use property accessors. Imagine you have a GENERIC abstract class with lots of implementation goodness to inherit into 8 concrete subclasses:
这里需要使用属性访问器。假设您有一个泛型抽象类,它具有很多实现优点,可以继承到8个具体的子类中:
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
}
Now exactly how should you annotate this class? The answer is YOU CAN'T annotate it at all with either field or property access because you can't specify the target entity at this point. You HAVE to annotate the concrete implementations. But since the persisted properties are declared in this superclass, you MUST used property access in the subclasses.
现在,你该如何注释这个类呢?答案是你不能用字段或属性访问来注释它,因为你现在不能指定目标实体。您必须注释具体的实现。但是由于持久化属性是在这个超类中声明的,所以必须在子类中使用属性访问。
Field access is not an option in an application with abstract generic super-classes.
在具有抽象泛型超类的应用程序中,字段访问不是一个选项。
#5
33
I tend to prefer and to use property accessors:
我倾向于使用属性访问器:
- I can add logic if the need arises (as mentioned in the accepted answer).
- 如果需要,我可以添加逻辑(如所接受的答案中所提到的)。
- it allows me to call
foo.getId()
without initializing a proxy (important when using Hibernate, until HHH-3718 get resolved). - 它允许我在不初始化代理(在使用Hibernate时很重要,直到HHH-3718得到解决)的情况下调用foo.getId()。
Drawback:
缺点:
- it makes the code less readable, you have for example to browse a whole class to see if there are
@Transient
around there. - 它使代码可读性降低,例如,您必须浏览整个类,以查看是否有@Transient。
#6
13
That really depends on a specific case -- both options are available for a reason. IMO it boils down to three cases:
这取决于具体情况——这两种选择都是有原因的。在我看来,可以归结为三种情况:
- setter has some logic that should not be executed at the time of loading an instance from a database; for example, some value validation happens in the setter, however the data coming from db should be valid (otherwise it would not get there (: ); in this case field access is most appropriate;
- setter具有在从数据库加载实例时不应执行的某些逻辑;例如,一些值验证发生在setter中,但是来自db的数据应该是有效的(否则它不会到达那里(:);在这种情况下,字段访问是最合适的;
- setter has some logic that should always be invoked, even during loading of an instance from db; for example, the property being initialised is used in computation of some calculated field (e.g. property -- a monetary amount, calculated property -- a total of several monetary properties of the same instance); in this case property access is required.
- setter有一些逻辑应该始终被调用,即使是在从db加载实例时;例如,被初始化的属性用于计算某些计算字段(例如,属性——货币数量、计算属性——同一实例的若干货币属性的总和);在这种情况下,需要属性访问。
- None of the above cases -- then both options are applicable, just stay consistent (e.i. if field access is the choice in this situation then use it all the time in similar situation).
- 上述情况都不存在——那么这两个选项都是适用的,只要保持一致(例如,如果在这种情况下选择字段访问,那么在类似的情况下始终使用字段访问)。
#7
12
I would strongly recommend field access and NOT annotations on the getters (property access) if you want to do anything more in the setters than just setting the value (e.g. Encryption or calculation).
如果您想在setter中做更多的事情,而不只是设置值(例如加密或计算),那么我强烈推荐字段访问,而不是getters(属性访问)上的注释。
The problem with the property access is that the setters are also called when the object is loaded. This has worked for me fine for many month until we wanted to introduce encryption. In our use case we wanted to encrypt a field in the setter and decrypt it in the getter. The problem now with property access was that when Hibernate loaded the object it was also calling the setter to populate the field and thus was encrypting the encrypted value again. This post also mentions this: Java Hibernate: Different property set function behavior depending on who is calling it
属性访问的问题是,在加载对象时还调用setter。在引入加密之前,这对我来说已经有好几个月了。在我们的用例中,我们希望加密setter中的字段并在getter中解密它。属性访问现在的问题是,当Hibernate加载对象时,它还调用setter来填充字段,从而再次加密加密加密的值。这篇文章还提到:Java Hibernate:不同的属性集函数行为取决于调用它的人
This has cause me headaches until I remembered the difference between field access and property access. Now I have moved all my annotations from property access to field access and it works fine now.
这让我头疼,直到我想起字段访问和属性访问之间的区别。现在,我已经将所有注释从属性访问移动到字段访问,现在它可以正常工作了。
#8
7
I think annotating the property is better because updating fields directly breaks encapsulation, even when your ORM does it.
我认为对属性进行注释更好,因为更新字段会直接破坏封装,即使您的ORM完成了它。
Here's a great example of where it will burn you: you probably want your annotations for hibernate validator & persistence in the same place (either fields or properties). If you want to test your hibernate validator powered validations which are annotated on a field, you can't use a mock of your entity to isolate your unit test to just the validator. Ouch.
这里有一个很好的例子,说明它将在哪里烧坏您:您可能希望hibernate validator & persistence的注释位于相同的位置(字段或属性)。如果您想测试您的hibernate验证器支持的验证,这些验证被注释在一个字段中,您不能使用实体的模拟来将单元测试隔离为验证器。哎哟。
#9
6
I believe property access vs. field access is subtly different with regards to lazy initialisation.
我认为属性访问和字段访问在延迟初始化方面有着微妙的不同。
Consider the following mappings for 2 basic beans:
考虑以下两个基本bean的映射:
<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>
And the following unit tests:
及以下单元测试:
@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();
}
You will see the subtle difference in the selects required:
您将看到所需选择的细微差别:
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
That is, calling fb.getId()
requires a select, whereas pb.getId()
does not.
也就是说,调用fb.getId()需要选择,而pb.getId()则不需要。
#10
5
I prefer using field access for the following reasons:
我喜欢使用字段访问,原因如下:
-
The property access can lead to very nasty bugs when implementing equals/hashCode and referencing fields directly (as opposed through their getters). This is because the proxy is only initialized when the getters are accessed, and a direct-field access would simply return null.
当实现equals/hashCode并直接引用字段(而不是通过它们的getter)时,属性访问会导致非常讨厌的bug。这是因为只有在访问getter时才初始化代理,而直接字段访问只会返回null。
-
The property access requires you to annotate all utility methods (e.g. addChild/removeChild) as
@Transient
.属性访问要求您将所有实用方法(例如addChild/removeChild)注释为@Transient。
-
With field access we can hide the @Version field by not exposing a getter at all. A getter can also lead to adding a setter as well, and the
version
field should never be set manually (which can lead to very nasty issues). All version incrementation should be triggered through OPTIMISTIC_FORCE_INCREMENT or PESSIMISTIC_FORCE_INCREMENT explicit locking.通过字段访问,我们可以隐藏@Version字段,而不需要公开getter。getter也可能导致添加setter,而且不应该手动设置版本字段(这会导致非常棘手的问题)。所有版本增量都应该通过OPTIMISTIC_FORCE_INCREMENT或invalimistic_force_increment显式锁定来触发。
#11
2
我们在那了吗
That's an old presentation but Rod suggests that annotation on property access encourages anemic domain models and should not be the "default" way to annotate.
这是一个旧的表示,但Rod建议属性访问的注释鼓励了贫血的域模型,不应该是“默认”的注释方式。
#12
2
Another point in favor of field access is that otherwise you are forced to expose setters for collections as well what, for me, is a bad idea as changing the persistent collection instance to an object not managed by Hibernate will definitely break your data consistency.
另一个支持字段访问的观点是,否则您将*为集合公开setter,对我来说,将持久集合实例更改为非Hibernate管理的对象肯定会破坏数据一致性,这对我来说是一个坏主意。
So I prefer having collections as protected fields initialized to empty implementations in the default constructor and expose only their getters. Then, only managed operations like clear()
, remove()
, removeAll()
etc are possible that will never make Hibernate unaware of changes.
因此,我更喜欢在默认构造函数中将集合作为受保护字段初始化为空实现,并只公开它们的getter。然后,只有像clear()、remove()、removeAll()等托管操作才有可能使Hibernate不知道更改。
#13
2
I prefer fields, but I've run into one situation that seems to force me to place the annotations on getters.
我更喜欢字段,但我遇到了一种情况,似乎迫使我将注释放在getter上。
With the Hibernate JPA implementation, @Embedded
doesn't seem to work on fields. So that has to go on the getter. And once you put that on the getter, then the various @Column
annotations have to go on the getters too. (I think Hibernate doesn't want mixing fields and getters here.) And once you're putting @Column
on getters in one class, it probably makes sense to do that throughout.
使用Hibernate JPA实现,@嵌入式似乎不能在字段上工作。所以它必须在getter上。一旦你把它放在getter上,那么各种@Column注释也必须放在getter上。(我认为Hibernate不希望在这里混合字段和getter。)一旦你把@Column放在一个类中,那么在整个类中这样做是有意义的。
#14
2
I favor field accessors. The code is much cleaner. All the annotations can be placed in one section of a class and the code is much easier to read.
我喜欢字段访问器。代码要干净得多。所有注释都可以放在类的一个部分中,代码更容易阅读。
I found another problem with property accessors: if you have getXYZ methods on your class that are NOT annotated as being associated with persistent properties, hibernate generates sql to attempt to get those properties, resulting in some very confusing error messages. Two hours wasted. I did not write this code; I have always used field accessors in the past and have never run into this issue.
我发现了属性访问器的另一个问题:如果您的类上有getXYZ方法,但没有注释为与持久属性相关联,那么hibernate会生成sql来尝试获取这些属性,从而导致一些非常混乱的错误消息。浪费了两个小时。我没有写这段代码;我过去一直使用字段访问器,从来没有遇到过这个问题。
Hibernate versions used in this app:
本应用使用的Hibernate版本:
<!-- 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>
#15
1
I had the same question regarding accesstype in hibernate and found some answers here.
我对冬眠中的accesstype也有同样的问题,在这里我找到了一些答案。
#16
1
I have solved lazy initialisation and field access here Hibernate one-to-one: getId() without fetching entire object
我在这里解决了延迟初始化和字段访问Hibernate一对一:getId(),而不获取整个对象
#17
1
We created entity beans and used getter annotations. The problem we ran into is this: some entities have complex rules for some properties regarding when they can be updated. The solution was to have some business logic in each setter that determines whether or not the actual value changed and, if so, whether the change should be allowed. Of course, Hibernate can always set the properties, so we ended up with two groups of setters. Pretty ugly.
我们创建了实体bean并使用了getter注释。我们遇到的问题是:一些实体对于某些属性有关于何时可以更新的复杂规则。解决方案是在每个setter中都包含一些业务逻辑,以确定实际值是否更改,如果更改,是否应该允许更改。当然,Hibernate总是可以设置属性,所以我们最后得到了两组setter。很丑。
Reading previous posts, I also see that referencing the properties from inside the entity could lead to issues with collections not loading.
在阅读之前的文章时,我还发现从实体内部引用属性可能会导致集合不加载的问题。
Bottom line, I would lean toward annotating the fields in the future.
总之,我倾向于在将来注释这些字段。
#18
1
By default, JPA providers access the values of entity fields and map those fields to database columns using the entity’s JavaBean property accessor (getter) and mutator (setter) methods. As such, the names and types of the private fields in an entity do not matter to JPA. Instead, JPA looks at only the names and return types of the JavaBean property accessors. You can alter this using the @javax.persistence.Access
annotation, which enables you to explicitly specify the access methodology that the JPA provider should employ.
默认情况下,JPA提供程序访问实体字段的值,并使用实体的JavaBean属性访问器(getter)和mutator (setter)方法将这些字段映射到数据库列。因此,实体中的私有字段的名称和类型对JPA并不重要。相反,JPA只查看JavaBean属性访问器的名称和返回类型。您可以使用@javax.persistence更改它。Access annotation,它允许您显式地指定JPA提供者应该使用的访问方法。
@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}
The available options for the AccessType enum are PROPERTY (the default) and FIELD. With PROPERTY, the provider gets and sets field values using the JavaBean property methods. FIELD makes the provider get and set field values using the instance fields. As a best practice, you should just stick to the default and use JavaBean properties unless you have a compelling reason to do otherwise.
AccessType enum的可用选项是属性(默认)和字段。对于属性,提供者使用JavaBean属性方法获取和设置字段值。字段使提供程序获取并使用实例字段设置字段值。作为一种最佳实践,您应该坚持使用默认属性并使用JavaBean属性,除非您有令人信服的理由不这么做。
You can put these property annotations on either the private fields or the public accessor methods. If you use AccessType.PROPERTY
(default) and annotate the private fields instead of the JavaBean accessors, the field names must match the JavaBean property names. However, the names do not have to match if you annotate the JavaBean accessors. Likewise, if you use AccessType.FIELD
and annotate the JavaBean accessors instead of the fields, the field names must also match the JavaBean property names. In this case, they do not have to match if you annotate the fields. It’s best to just be consistent and annotate the JavaBean accessors for AccessType.PROPERTY
and the fields for AccessType.FIELD
.
您可以将这些属性注释放在私有字段或公共访问器方法上。如果你使用AccessType。属性(默认)并注释私有字段而不是JavaBean访问器,字段名必须与JavaBean属性名匹配。但是,如果您注释了JavaBean访问器,则不必匹配名称。同样,如果你使用AccessType。字段并注释JavaBean访问器而不是字段,字段名也必须与JavaBean属性名匹配。在这种情况下,如果您对字段进行注释,它们就不需要匹配。最好保持一致并为AccessType注释JavaBean访问器。属性和用于AccessType.FIELD的字段。
It is important that you should never mix JPA property annotations and JPA field annotations in the same entity. Doing so results in unspecified behavior and is very likely to cause errors.
重要的是,您不应该在同一个实体中混合JPA属性注释和JPA字段注释。这样做会导致未指定的行为,并且很可能导致错误。
#19
0
Normally beans are POJO, so they have accessors anyway.
通常情况下,bean是POJO,所以它们有访问器。
So the question is not "which one is better?", but simply "when to use field access?". And the answer is "when you don't need a setter/getter for the field!".
所以问题不是“哪个更好?”,而只是“何时使用字段访问?”答案是“当你不需要一个setter/getter时!”
#20
0
i thinking about this and i choose method accesor
我考虑了一下,选择了方法accesor
why?
为什么?
because field and methos accesor is the same but if later i need some logic in load field, i save move all annotation placed in fields
因为field和methos accesor是相同的,但是如果以后我需要在load字段中使用一些逻辑,我就保存放在字段中的move all annotation
regards
问候
Grubhart
Grubhart
#21
0
To make your classes cleaner, put the annotation in the field then use @Access(AccessType.PROPERTY)
要使类更清晰,请将注释放在字段中,然后使用@Access(AccessType.PROPERTY)