2013-12-16 2 views
0

Я работаю над контроллером Spring MVC и представлениями для реализации операций CRUD для простого объекта с именем Partner. Операция обновления меня беспокоит. Кажется, мне нужно написать несколько строк кода вручную, что я ожидал, что Spring MVC позаботится автоматически. Есть ли лучшая практика, которую мне не хватает здесь?Обновление Spring MVC без избыточного кода?

Вот мое мнение:

<%@ include file="include.jsp"%> 

<form:form commandName="partner"> 
    <input type="hidden" name="_method" value="PUT" /> 
    <table> 
     <tr> 
      <td>Id:</td> 
      <td><form:input path="id" disabled="true" /></td> 
     </tr> 
     <tr> 
      <td>Name:</td> 
      <td><form:input path="name" /></td> 
     </tr> 
     <tr> 
      <td>Logo:</td> 
      <td><form:input path="logo" /></td> 
     </tr> 
     <tr> 
      <td>On-screen text:</td> 
      <td><form:textarea path="onScreenText" /></td> 
     </tr> 
     <tr> 
      <td colspan="2"><input type="submit" value="Save Changes" /></td> 
     </tr> 
    </table> 
    </form:form> 

И вот мой метод контроллера для операции обновления:

@RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT) 
public ModelAndView updatePartner(@ModelAttribute Partner partner, @PathVariable int partnerId) { 
    EntityManager entityManager = DatabaseHelper.getEntityManager(); 
    try { 
     Partner partnerToUpdate = entityManager.find(Partner.class, partnerId); 
     entityManager.getTransaction().begin(); 
     partnerToUpdate.setId(partnerId); 
     partnerToUpdate.setName(partner.getName()); 
     partnerToUpdate.setLogo(partner.getLogo()); 
     partnerToUpdate.setOnScreenText(partner.getOnScreenText()); 
     entityManager.persist(partnerToUpdate); 
     entityManager.getTransaction().commit(); 
    } 
    finally { 
     entityManager.close(); 
    } 
    return new ModelAndView("redirect:/partner"); 
} 

Строки кода, смущающие меня являются:

Partner partnerToUpdate = entityManager.find(Partner.class, partnerId); 
partnerToUpdate.setId(partnerId); 
partnerToUpdate.setName(partner.getName()); 
partnerToUpdate.setLogo(partner.getLogo()); 
partnerToUpdate.setOnScreenText(partner.getOnScreenText()); 

Do I действительно нужно искать существующего Партнера в базе данных и явно обновлять каждое поле этого объекта? У меня уже есть объект Partner со всеми нужными значениями. Невозможно ли сохранить этот объект непосредственно в базе данных?

Я уже просмотрел Spring MVC CRUD controller best pactice, но это не совсем отвечало на мой вопрос.

+1

Вы можете попробовать использовать 'партнера .setId (partnerToUpdate.getId()); entityManager.merge (partner); ', но он работает только в том случае, если' partner' является полным объектом. –

+0

@AVolpe, ваше предложение использовать слияние. –

+0

Тогда я добавлю ответ. –

ответ

0

Вы можете использовать merge обновить нужные значения, что-то вроде:

@RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT) 
    public ModelAndView updatePartner(@ModelAttribute Partner partner, @PathVariable int partnerId) { 
     EntityManager entityManager = DatabaseHelper.getEntityManager(); 
     try { 
      entityManager.getTransaction().begin(); 
      partner.setId(partnerId); 
      entityManager.merge(partner); 
      entityManager.getTransaction().commit(); 
     } 
     finally { 
      entityManager.close(); 
     } 
     return new ModelAndView("redirect:/partner"); 
    } 

Кроме того, я рекомендую Вам использовать поддержку транзакций DAO Pattern и Spring с @Transactional и @Repository

1

В качестве одного из возможных предложений вы можете найти существующий объект Partner как часть создания модели, чтобы экземпляр этой модели обратился к форме, а Spring привязывает поля непосредственно к ней. Одним из способов достижения этого было бы создание явного метода в контроллере, ответственном за создание модели.

Например:

@ModelAttribute("partner") 
public Partner createModel(@PathVariable int partnerId) { 
    Partner partner = entityManager.find(Partner.class, partnerId); 
    return partner; 
} 

И тогда вы можете удалить копирование из метода updatePartner - потому, что весна будет уже связаны поля формы непосредственно загруженного Partner объекта.

@RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT) 
public ModelAndView updatePartner(@ModelAttribute("partner") Partner partner) { 
    EntityManager entityManager = DatabaseHelper.getEntityManager(); 
    try { 
     entityManager.getTransaction().begin(); 
     entityManager.persist(partner); 
     entityManager.getTransaction().commit(); 
    } 
    finally { 
     entityManager.close(); 
    } 
    return new ModelAndView("redirect:/partner"); 
} 

Один нюанс - так как метод createModel будет вызываться для каждого запроса к контроллеру (не только updatePartner), переменная partnerId путь должен был бы присутствовать во всех запросах.

Существует сообщение here, в котором рассматривается решение этой проблемы.

+1

Вам действительно нужно иметь сервис/хранилище, чтобы скрыть использование «EntityManager», контроллер не является местом для запуска/остановки транзакции. И вы, вероятно, захотите использовать декларативное управление tsw springs, поэтому вам не нужно это делать самостоятельно. –

+0

@ M.Deinum - согласился. Я снял код из OP, чтобы проиллюстрировать свой ответ. Разумеется, разделить детали персистентности с контроллером и скрыть EntityManager. –

+0

Спасибо.Я смог следовать предложению AVolpe и не нуждался в создании отдельного метода, аннотированного с помощью ModelAttribute. Я буду следовать рекомендациям M. Deinum и @Will Keeling, чтобы создать отдельный сервис/репозиторий. –