2016-02-21 4 views
0

У меня есть таблица с уникальным ограничением в одном поле, и я хочу настроить Hibernate EntityManager, чтобы она вставляла новую запись только в том случае, если такой записи уже нет и будет обновляться иначе.Hibernate: Вставка обновления с EntityManager

Мой POJO для таблицы выглядит выглядит так:

@Entity 
@Table(name = "links", uniqueConstraints = { 
     @UniqueConstraint(columnNames = "link", name = "uk_link") 
    }) 
public class Link { 

    private long linkId; 
    private String link; 
    private String data; 
    private String metadata; 

    private List<Result> results; 

    @Id 
    @Column(name="link_id") 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    public long getLinkId() { 
     return linkId; 
    } 

    public void setLinkId(long linkId) { 
     this.linkId = linkId; 
    } 

    public String getLink() { 
     return link; 
    } 

    public void setLink(String link) { 
     this.link = link; 
    } 

    public String getData() { 
     return data; 
    } 

    public void setData(String data) { 
     this.data = data; 
    } 

    public String getMetadata() { 
     return metadata; 
    } 

    public void setMetadata(String metadata) { 
     this.metadata = metadata; 
    } 

    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "link") 
    public List<Result> getResults() { 
     return results; 
    } 

    public void setResults(List<Result> results) { 
     this.results = results; 
    } 

    @Override 
    public String toString() { 
     return "Link [linkId=" + linkId + ", link=" + link + ", data=" + data + ", metadata=" + metadata + "]"; 
    } 

    public boolean isDataEquals(String data) { 
     if (this.data == null) { 
      if (data != null) 
       return false; 
     } else if (!this.data.equals(data)) 
      return false; 
     return true; 
    } 

    public boolean isMetadataEquals(String metadata) { 
     if (this.metadata == null) { 
      if (metadata != null) 
       return false; 
     } else if (!this.metadata.equals(metadata)) 
      return false; 
     return true; 
    } 
} 

И я пытаюсь решить необходимые изменения с помощью этого кода:

public Link selectByLink(String link) { 
    return entityManager 
      .createQuery("select l from Link l WHERE l.link = :link", Link.class) 
      .setParameter("link", link) 
      .getSingleResult(); 
} 

public void insert(Link link) { 
    this.entityManager.persist(link); 
} 

public Link update(Link link) { 
    return this.entityManager.merge(link); 
} 

public void save(Link link) { 
    if (link.getLinkId() == 0) { 
     Link _existing = selectByLink(link.getLink()); 
     if (null != _existing) { 
      link.setLinkId(_existing.getLinkId()); 
      if (!_existing.isDataEquals(link.getData()) || 
       !_existing.isMetadataEquals(link.getMetadata())) { 
       update(link); 
      } 
     } else 
      insert(link); 
    } 
} 

В журнале Spring, я вижу один дополнительный выберите:

Hibernate: select link0_.link_id as link_id1_0_, link0_.data as data2_0_, link0_.link as link3_0_, link0_.metadata as metadata4_0_ from links link0_ where link0_.link=? 
Hibernate: select link0_.link_id as link_id1_0_1_, link0_.data as data2_0_1_, link0_.link as link3_0_1_, link0_.metadata as metadata4_0_1_, results1_.link_id as link_id1_1_3_, results1_.text_id as text_id2_1_3_, results1_.link_id as link_id1_1_0_, results1_.text_id as text_id2_1_0_, results1_.found as found3_1_0_, results1_.level as level4_1_0_ from links link0_ left outer join results results1_ on link0_.link_id=results1_.link_id where link0_.link_id=? 
Hibernate: update links set data=?, link=?, metadata=? where link_id=? 

Я думаю, это происходит потому, что я использую функцию слияния, но если я не ищу o bject id перед его объединением, слияние попытается вставить объект вместо его обновления. Есть ли способ просто обновить объект, не тестируя его в первую очередь?

И не связанный вопрос, SQL выглядит очень грязно. все это link0_.link_id as link_id1_0_, они могут быть подавлены?

+0

У вас были улучшения на этом? –

+0

Нет, я проигнорировал спящий режим на данный момент и переключился на шаблоны – Dmitry

ответ

0

Дополнительное соединение происходит в результате вашего ленивого отношения ко многим. Помимо выбора самой ссылки, выполняется дополнительный оператор выбора для загрузки коллекции (это корень известной проблемы N + 1).

И для выбора, выполненного перед обновлением, похоже, что спящий режим сохраняется by default, когда объекты отсоединяются. Если вы хотите этого избежать, вы должны играть с его конфигурацией (есть свойство select-before-update) или самостоятельно написать запрос на обновление. Вы могли бы также попытаться избежать Spring, отсоединяя объекты Hibernate.

Смежные вопросы