Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA-EclipseLink在合并实体时对关系发出额外的SELECT请求_Java_Jpa_Eclipselink_Fetch_Relationships - Fatal编程技术网

Java JPA-EclipseLink在合并实体时对关系发出额外的SELECT请求

Java JPA-EclipseLink在合并实体时对关系发出额外的SELECT请求,java,jpa,eclipselink,fetch,relationships,Java,Jpa,Eclipselink,Fetch,Relationships,我对使用merge方法更新实体时出现的“奇怪”行为提出了一个问题 我有一个实体“Personne”,它有两个关系(fetch=LAZY)。我有一个HTML表单,用于仅修改该实体的字段。当使用merge方法保存该实体时,我看到对所有关系的SELECT请求 我不明白为什么要进行这些选择,我想避免这些选择,因为这种行为加载的数据可能是“巨大的” 这就是我的实体: @Entity @Table(name="personne") @NamedQuery(name="Personne.findAll", q

我对使用merge方法更新实体时出现的“奇怪”行为提出了一个问题

我有一个实体“Personne”,它有两个关系
(fetch=LAZY)
。我有一个HTML表单,用于仅修改该实体的字段。当使用merge方法保存该实体时,我看到对所有关系的SELECT请求

我不明白为什么要进行这些选择,我想避免这些选择,因为这种行为加载的数据可能是“巨大的”

这就是我的实体:

@Entity
@Table(name="personne")
@NamedQuery(name="Personne.findAll", query="SELECT p FROM Personne p")
public class Personne implements Serializable {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(unique=true, nullable=false)
private Integer id;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="date_naissance")
private Date dateNaissance;

@Column(length=75)
private String denomination;

@Column(length=75)
private String nom;

@Column(precision=10, scale=2)
private BigDecimal poids;

@Column(length=75)
private String prenom;

@Column(precision=10, scale=2)
private BigDecimal taille;

//bi-directional many-to-one association to Contact
@OneToMany(mappedBy="personne", fetch = FetchType.LAZY)
private List<Contact> contacts;

//bi-directional many-to-one association to Log
@OneToMany(mappedBy="personne", fetch = FetchType.LAZY)
private List<Logs> logs;

//bi-directional many-to-one association to PersonneHasAdresse
@OneToMany(mappedBy="personne", fetch = FetchType.LAZY)
private List<PersonneHasAdresse> personneHasAdresses;

//bi-directional many-to-one association to PersonneHasPersonne
@OneToMany(mappedBy="parent", fetch = FetchType.LAZY)
private List<PersonneHasPersonne> personneHasPersonnesParent;

//bi-directional many-to-one association to PersonneHasPersonne
@OneToMany(mappedBy="child", fetch = FetchType.LAZY)
private List<PersonneHasPersonne> personneHasPersonnesChild;

public Personne() {
}

public Integer getId() {
    return this.id;
}

public void setId(Integer id) {
    this.id = id;
}

public Date getDateNaissance() {
    return this.dateNaissance;
}

public void setDateNaissance(Date dateNaissance) {
    this.dateNaissance = dateNaissance;
}

public String getDenomination() {
    return this.denomination;
}

public void setDenomination(String denomination) {
    this.denomination = denomination;
}

public String getNom() {
    return this.nom;
}

public void setNom(String nom) {
    this.nom = nom;
}

public BigDecimal getPoids() {
    return this.poids;
}

public void setPoids(BigDecimal poids) {
    this.poids = poids;
}

public String getPrenom() {
    return this.prenom;
}

public void setPrenom(String prenom) {
    this.prenom = prenom;
}

public BigDecimal getTaille() {
    return this.taille;
}

public void setTaille(BigDecimal taille) {
    this.taille = taille;
}

@JsonIgnore
public List<Contact> getContacts() {
    return this.contacts;
}

public void setContacts(List<Contact> contacts) {
    this.contacts = contacts;
}

public Contact addContact(Contact contact) {
    this.getContacts().add(contact);
    contact.setPersonne(this);

    return contact;
}

public Contact removeContact(Contact contact) {
    this.getContacts().remove(contact);
    contact.setPersonne(null);

    return contact;
}

@JsonIgnore
public List<Logs> getLogs() {
    return this.logs;
}

public void setLogs(List<Logs> logs) {
    this.logs = logs;
}

public Logs addLog(Logs log) {
    this.getLogs().add(log);
    log.setPersonne(this);

    return log;
}

public Logs removeLog(Logs log) {
    this.getLogs().remove(log);
    log.setPersonne(null);

    return log;
}

@JsonIgnore
public List<PersonneHasAdresse> getPersonneHasAdresses() {
    return this.personneHasAdresses;
}

public void setPersonneHasAdresses(List<PersonneHasAdresse> personneHasAdresses) {
    this.personneHasAdresses = personneHasAdresses;
}

@JsonIgnore
public PersonneHasAdresse addPersonneHasAdress(PersonneHasAdresse personneHasAdress) {
    this.getPersonneHasAdresses().add(personneHasAdress);
    personneHasAdress.setPersonne(this);

    return personneHasAdress;
}

public PersonneHasAdresse removePersonneHasAdress(PersonneHasAdresse personneHasAdress) {
    this.getPersonneHasAdresses().remove(personneHasAdress);
    personneHasAdress.setPersonne(null);

    return personneHasAdress;
}

@JsonIgnore
public List<PersonneHasPersonne> getPersonneHasPersonnesParent() {
    return this.personneHasPersonnesParent;
}

public void setPersonneHasPersonnesParent(List<PersonneHasPersonne> personneHasPersonnesParent) {
    this.personneHasPersonnesParent = personneHasPersonnesParent;
}

public PersonneHasPersonne addPersonneHasPersonnesParent(PersonneHasPersonne personneHasPersonnesParent) {
    this.getPersonneHasPersonnesParent().add(personneHasPersonnesParent);
    personneHasPersonnesParent.setParent(this);

    return personneHasPersonnesParent;
}

public PersonneHasPersonne removePersonneHasPersonnesParent(PersonneHasPersonne personneHasPersonnesParent) {
    this.getPersonneHasPersonnesParent().remove(personneHasPersonnesParent);
    personneHasPersonnesParent.setParent(null);

    return personneHasPersonnesParent;
}

@JsonIgnore
public List<PersonneHasPersonne> getPersonneHasPersonnesChild() {
    return this.personneHasPersonnesChild;
}

public void setPersonneHasPersonnesChild(List<PersonneHasPersonne> personneHasPersonnesChild) {
    this.personneHasPersonnesChild = personneHasPersonnesChild;
}

public PersonneHasPersonne addPersonneHasPersonnesChild(PersonneHasPersonne personneHasPersonnesChild) {
    this.getPersonneHasPersonnesChild().add(personneHasPersonnesChild);
    personneHasPersonnesChild.setChild(this);

    return personneHasPersonnesChild;
}

public PersonneHasPersonne removePersonneHasPersonnesChild(PersonneHasPersonne personneHasPersonnesChild) {
    this.getPersonneHasPersonnesChild().remove(personneHasPersonnesChild);
    personneHasPersonnesChild.setChild(null);

    return personneHasPersonnesChild;
}
在UPDATE语句之前,会选择联系人和日志。 有人知道为什么吗?这是正常的行为吗?如果是,如何避免

非常感谢您的帮助


编辑1:

所有层(从REST到DAO)的完整代码:

@Path(“人员”)
@产生({MediaType.APPLICATION_JSON})
@使用({MediaType.APPLICATION_JSON})
公共类人员名单{
私人人员服务人员服务=新人员服务();
...
@放
@路径(“{id}”)
公共响应更新(@PathParam(“id”)整数id,Personne Personne){
if(personne==null | |!id.equals(personne.getId()){
返回Response.status(status.BAD_REQUEST.build();
}
this.personeservices.merge(personne);
返回Response.noContent().build();
}
@职位
公众响应创建(persone persone){
Personne createdPersonne=this.personeServices.persist(Personne);
返回Response.created(URI.create(“persones/”+createdPersonne.getId()).build();
}
...
}
公共类PersonneServices扩展了AbstractBasicServices{
公共人员服务(){
super(newpersonedao(),Personne.class,“poi.model”);
}
}
公共类人员DAO扩展了AbstractBasicDao{
}
公共抽象类AbstractBasicServices{
私渡道;
私人课堂;
专用字符串存储单元;
公共AbstractBasicServices(AbstractBasicDao、类clazz、字符串持久化单元){
this.dao=dao;
this.clazz=clazz;
this.persistUnit=persistUnit;
} 
公共电子商务(E obj){
EntityManager em=persistenceManager.getInstance().getEm(this.persistUnit);
E res=null;
试一试{
EntityTransaction t=em.getTransaction();
试一试{
t、 begin();
res=this.dao.persist(obj,em);
t、 提交();
}最后{
if(t.isActive()){
t、 回滚();
}
}
}最后{
em.close();
}
返回res;
}
//合并方法是第一篇文章中的方法。
}
公共抽象类AbstractBasicDao{
公共T持久化(T对象、实体管理器em){
em.persist(obj);
em.flush();
em.refresh(obj);
返回obj;
}
公共T合并(T对象、实体管理器em){
返回em.merge(obj);
}
}

编辑2:

回顾之后,我(在persistence.xml中)将“共享缓存模式”改为“无”。很明显,实体经理需要重新加载关系(愚蠢的我…)。 所以我把它设为“默认”

我进行了以下测试(每次测试我都会重新启动服务器):

  • (测试1-1)创建新实体(持久化):插入+选择关系
  • (测试1-2)更新上一个实体(合并):更新(无选择)
  • (测试2-1)更新实体(合并):更新+选择关系
  • (测试2-2)更新同一实体(合并):更新(无选择)
这看起来正常吗


编辑3:

我发布了整个人事实体,现在我看到了我的错误。我使用@JsonIgnore来避免在查询显示人员属性列表时加载关系,因为关系是编组的。但是,解组并没有使间接列表后退。我删除了注释

我创建了一个包装器,它只包含JAX-RS层所需的属性,并在需要更新时将字段更新到相应的实体,并且没有更多的选择


谢谢大家抽出时间。

我无法复制此内容。

在调用
merge()
之前,能否验证以下表达式是否返回false

((org.eclipse.persistence.indirection.IndirectContainer)obj.getContacts()).isInstantiated()
(假设您有一个名为
getContacts()
的getter,它只返回实体类中的字段
contacts

如果它返回
false
,那么这将是一个“奇怪”的行为,需要进一步调查

如果它返回
true
(很可能是这种情况),那么这个延迟加载的集合之前已经被访问过,因此EclipseLink需要检查数据库中是否有更改。

在这种情况下,请事先检查哪些代码访问该集合(使用断点来解决此问题)。

合并前是否访问了联系人和日志列表?检查它们是否在调试器中填充-如果是,那么JPA必须检查您在合并时没有修改列表,这需要数据库命中。你好,Chris,谢谢您的回复。否,在合并之前无法访问这些列表。我将断点放在getter/setter上,使其为sur,但没有命中。字段也为空。您在什么环境中运行?您是否在任何地方访问关系,例如在toString方法中?我正在Tomcat7下运行应用程序。webapp由AngularJS制作,其余的Webservices由JAX-RS(+Jackson)制作。bean中没有toString()方法。我还更新了帖子。你是如何获得合并实体的?看起来您可能没有在JAX-RS中映射该集合,因此它没有被传递回进行合并-JPA需要将这个空列表合并到一个非迁移列表中
@Path("personnes")
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
public class PersonnesRest {

    private PersonneServices personneServices = new PersonneServices();

    ...

    @PUT
    @Path("{id}")
    public Response update(@PathParam("id") Integer id, Personne personne) {
        if (personne == null || !id.equals(personne.getId())) {
            return Response.status(Status.BAD_REQUEST).build();
        }

        this.personneServices.merge(personne);
        return Response.noContent().build();
    }

    @POST
    public Response create(Personne personne) {
        Personne createdPersonne = this.personneServices.persist(personne);
        return Response.created(URI.create("personnes/" + createdPersonne.getId())).build();
    }

    ...

}

public class PersonneServices extends AbstractBasicServices<Personne> {

    public PersonneServices() {
        super(new PersonneDao(), Personne.class, "poi.model");
    }
}

public class PersonneDao extends AbstractBasicDao<Personne> {

}

public abstract class AbstractBasicServices<E> {

    private AbstractBasicDao<E> dao;

    private Class<E> clazz;

    private String persistUnit;

    public AbstractBasicServices(AbstractBasicDao<E> dao, Class<E> clazz, String persistUnit) {
        this.dao = dao;
        this.clazz = clazz;
        this.persistUnit = persistUnit;
    } 

public E persist(E obj) {
        EntityManager em = PersitenceManager.getInstance().getEm(this.persistUnit);
        E res = null;

        try {
            EntityTransaction t = em.getTransaction();
            try {
                t.begin();
                res = this.dao.persist(obj, em);
                t.commit();
            } finally {
                if (t.isActive()) {
                    t.rollback();
                }
            }
        } finally {
            em.close();
        }

        return res;
    }

// The merge method is the one in first post.

}

public abstract class AbstractBasicDao<T> {
    public T persist(T obj, EntityManager em) {
        em.persist(obj);
        em.flush();
        em.refresh(obj);
        return obj;
    }

    public T merge(T obj, EntityManager em) {
        return em.merge(obj);
    }
}
((org.eclipse.persistence.indirection.IndirectContainer)obj.getContacts()).isInstantiated()