Java 为什么在使用 JPA 映射类时应该在 getter 或 setter 上添加注释?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4188048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why should anybody put annotations on the getters or setters when using JPA to map the classes?
提问by Kawu
Subject says it all... I see no advantage of people declaring annotations on the getters and/or setters so far. For me this only has the disadvantage of spreading the annotations over the class, which can make the class more unreadable.
主题说明了一切......到目前为止,我认为人们在 getter 和/或 setter 上声明注释没有任何好处。对我来说,这唯一的缺点是将注释散布在类上,这会使类更难读。
Putting the annotations on the fields clearly reduces the amount of code to post when needing help. This is just a tiny advantage though. But putting annotations on methods would serve no purpose to me.
将注释放在字段上显然可以减少需要帮助时发布的代码量。但这只是一个很小的优势。但是在方法上添加注释对我来说毫无用处。
采纳答案by axtavt
Putting annotations on methods forces JPA to access properties via methods. It makes sense when internal state of your object differs from the database schema:
在方法上添加注释会强制 JPA 通过方法访问属性。当对象的内部状态与数据库模式不同时,这是有道理的:
@Entity
public class Employee {
private String firstName;
private String lastName;
@Column(name = "EMP_NAME") // Due to legacy database schema
public String getName() {
return fisrtName + " " + lastName;
}
public void setName(String name) {
...
}
... Getters and setters for firstName and lastName with @Transient ...
}
In JPA 2.0 you can specify access type at fine-grained level with @Access
:
在 JPA 2.0 中,您可以使用以下命令在细粒度级别指定访问类型@Access
:
@Entity @Access(AccessType.FIELD)
public class Employee {
@Access(AccessType.PROPERTY) @Column(name = "EMP_NAME")
public String getName() { ... }
... other properties have field access ...
}
回答by Pascal Thivent
Why should anybody put annotations on the getters or setters when using JPA to map the classes?
为什么在使用 JPA 映射类时应该在 getter 或 setter 上添加注释?
As already mentioned, using property access allows to add logic in the getter, if the need arises.
如前所述,如果需要,使用属性访问允许在 getter 中添加逻辑。
But since the question is tagged hibernate, I'll mention another (huge) benefit: property access allows you to call foo.getId()
without initializing a proxy. You cannot get the same behavior when using field access. Emmanuel Bernard explains this limitation of field access as follows:
但是由于问题被标记为hibernate,我将提到另一个(巨大的)好处:属性访问允许您在foo.getId()
不初始化代理的情况下调用。使用字段访问时,您无法获得相同的行为。Emmanuel Bernard 解释了现场访问的这种限制如下:
That is unfortunate but expected. That's one of the limitations of field level access. Basically we have no way to know that getId() indeed only go and access the id field. So we need to load the entire object to be safe.
这是不幸的,但也是意料之中的。这是字段级访问的限制之一。基本上我们无法知道 getId() 确实只是去访问 id 字段。所以我们需要加载整个对象以确保安全。
So yes, using property access makes the code harder to read, you have for example to browse a whole class to see if there are any @Transient
around there. But for me, the benefit (at least with hibernate) outweighs this disadvantage by far.
所以是的,使用属性访问会使代码更难阅读,例如,您必须浏览整个类以查看那里是否有任何内容@Transient
。但对我来说,好处(至少对于hibernate 而言)远远超过了这个缺点。
Related questions
相关问题
- Hibernate Annotations - Which is better, field or property access?
- Hibernate generating SQL queries when accessing associated entity's id
References
参考
回答by Clint
The answers given are correct. Annotating methods instead of properties gives you:
给出的答案是正确的。注释方法而不是属性为您提供:
The right to use getId(), if it's marked as the @Id value, to get a foreign key value from a proxy object without actually loading it from the DB.
You can create getters/setters that update internal object state that is not in the database. I've used this when retrieving compressed state from the DB that I want to decompress within the object into a more usable internal member datum. The setters and getters set and get the compressed state, and the DB and Hibernate don't "know" about the uncompressed internal member.
有权使用 getId()(如果它被标记为 @Id 值)从代理对象获取外键值,而无需实际从数据库加载它。
您可以创建更新不在数据库中的内部对象状态的 getter/setter。我在从数据库中检索压缩状态时使用了它,我想在对象中将其解压缩为更可用的内部成员数据。setter 和 getter 设置并获取压缩状态,而 DB 和 Hibernate 不“知道”未压缩的内部成员。
There is one drawback I've hit:
我遇到了一个缺点:
A. Your setters have to be pretty simple. Hibernate expects them to do what would be accomplished by direct assignment to a member datum. A "setCategory" method that not only sets a category, but also updates the relevant Category object to show the relationship, may get you into trouble.
A. 你的二传手必须非常简单。Hibernate 期望它们通过直接分配给成员数据来完成。“setCategory”方法不仅设置类别,而且更新相关的类别对象以显示关系,可能会给您带来麻烦。
回答by Tarek
I am using annotations on the getters/setters because I have an API separated from the implementation, and I wanted to keep the API part completely framework-free, allowing me to switch frameworks or provide different implementations. For instance, right now I'm using spring-data-jpa, but with the API below I can easily switch to spring-jdbc or any other framework.
我在 getter/setter 上使用注解,因为我有一个与实现分离的 API,我想让 API 部分完全没有框架,允许我切换框架或提供不同的实现。例如,现在我正在使用 spring-data-jpa,但使用下面的 API,我可以轻松切换到 spring-jdbc 或任何其他框架。
What I did was define the interfaces for the controller, repository and the entity, as such:
我所做的是为控制器、存储库和实体定义接口,如下所示:
public interface MyEntityController<T extends MyEntity> {
Iterable<T> listEntities();
T getEntity(Long id);
}
public interface MyEntityService<T extends MyEntity> {
Iterable<T> findAll();
T findById(Long id);
}
public interface MyEntityRepository<T extends MyEntity> {
Iterable<T> findAll();
T findOne(Long id);
}
// no JPA annotations here
public abstract class MyEntity {
protected Long id;
protected String myField;
}
Next I just implement the MyEntity as follows, and use the MyEntityImpl for the Controller, Service and Repository implementations:
接下来,我只是按如下方式实现 MyEntity,并将 MyEntityImpl 用于 Controller、Service 和 Repository 实现:
@Entity
public class MyEntityImpl extends MyEntity {
@Id public long getId() { return id; }
@Column public String getMyField() { return myField };
// setters, etc
}
@Repository
public interface MyEntityRepositoryImpl extends MyEntityRepository, JPARepository<MyEntityImpl, Long> {
}
I have already tested it and it works fine. Just annotating the MyEntityImpl
with @Entity
would not have worked, as the superclass would need to be a @MappedSuperclass
.
我已经测试过它并且它工作正常。仅仅注释MyEntityImpl
with@Entity
是行不通的,因为超类需要是一个@MappedSuperclass
.