2011-12-24 21 views
45

Aquí está el código:¿Por qué utilizar la instancia devuelta después de guardar() en Spring Data JPA Repository?

@Repository 
public interface AccountRepository extends JpaRepository<Account, Long> {} 

JpaRepository del proyecto de Primavera de datos JPA.

Aquí está el código de prueba:

public class JpaAccountRepositoryTest extends JpaRepositoryTest { 
    @Inject 
    private AccountRepository accountRepository; 

    @Inject 
    private Account account; 

    @Test 
    @Transactional 
    public void createAccount() { 
     Account returnedAccount = accountRepository.save(account); 

     System.out.printf("account ID is %d and for returned account ID is %d\n", account.getId(), returnedAccount.getId()); 
    } 
} 

aquí está el resultado:

account ID is 0 and for returned account ID is 1 

Aquí es de CrudReporsitory.save() javadoc:

ahorra una entidad determinada. Utilice la instancia devuelta para realizar más operaciones ya que la operación de salvar podría haber cambiado la instancia de la entidad por completo.

Este es el código real para SimpleJpaRepository partir de la primavera de datos JPA:

@Transactional 
    public T save(T entity) { 
      if (entityInformation.isNew(entity)) { 
        em.persist(entity); 
        return entity; 
      } else { 
        return em.merge(entity); 
      } 
    } 

Entonces, la pregunta es ¿por qué tenemos que utilizar la instancia devuelta en lugar de la original? (Sí, debemos hacerlo, de lo contrario seguiremos trabajando con instancia separada, pero ¿por qué?)

El método original EntityManager.persist() devuelve vacío, por lo que nuestra instancia se adjunta al contexto de persistencia. ¿Se produce algo de magia proxy al pasar la cuenta para guardarla en el repositorio? ¿Es la limitación de la arquitectura del proyecto Spring Data JPA?

Respuesta

48

El método save(…) de la interfaz CrudRepository se supone que debe abstraer simplemente almacenar una entidad sin importar en qué estado se encuentre. Por lo tanto, no debe exponer la implementación real específica de la tienda, incluso si (como en el caso JPA) entre nuevas entidades para ser almacenadas y las existentes para ser actualizadas. Es por eso que el método se llama en realidad no save(…)create(…) o update(…). Devolvemos un resultado de ese método para permitir realmente que la implementación de la tienda devuelva una instancia completamente diferente, como potencialmente hace JPA cuando se invoca merge(…).

Así que por lo general es más bien una decisión API que sea indulgente con respecto a la implementación real y aplicando así el método de la APP como nosotros. No se realiza un masaje de proxy adicional a las entidades aprobadas.

+0

¿Puedo suponer que es seguro no utilizar los resultados de devolución para nuevas entidades? – danidacar

+2

¿Dónde hay documentación sobre el estado del objeto devuelto? Es decir, a veces devuelve campos actualizados (marcas de tiempo), a veces los campos no se actualizan desde la base de datos. – mmcrae

9

se ha perdido la segunda parte: si la entidad no es nuevo, se llama merge. merge copia el estado de su argumento en la entidad adjunta con el mismo ID, y devuelve la entidad adjunta. Si la entidad no es nueva y no utiliza la entidad devuelta, realizará modificaciones en una entidad separada.

+0

Sí, de acuerdo. Al menos, en este caso, es compatible con EntityManager. ¿Será mejor cambiar el nombre de este método a saveOrMerge()? – akazlou

+0

¿Qué pasa con los miembros transitorios del objeto? En el caso de cuando se fusiona, obtengo un nuevo Objeto real (que sinceramente no me importa) pero pierdo todos los valores transitorios de Objeto originales. –

Cuestiones relacionadas