Cómo ahorrar padre e hijo en una sola toma (JPA y Hibernate)

MDP :

Empiezo mostrando mi escenario.

Este es mi objeto padre:

@Entity
@Table(name="cart")
public class Cart implements Serializable{  

    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    @Column(name="id")
    private Integer id; 

    @OneToMany(mappedBy="cart", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<CartItem> cartItems; 

    ...
}

Este es mi objeto secundario:

@Entity
@Table(name="cart_item")
public class CartItem implements Serializable{  

    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    @Id
    @Column(name="id")
    private Integer id;     

    @ManyToOne
    @JoinColumn(name="cart_id", nullable=false)
    private Cart cart;

    ...
}

Como se puede ver mirando a la base de datos, en la tabla cart_item (objeto secundario) el campo cart_id tiene una clave externa al campo ID de la tabla de la cesta (objeto principal).

introducir descripción de la imagen aquí

Así es como me ahorro el objeto:

1) hay un restController que lee un objeto JSON:

@RestController
@RequestMapping(value = "rest/cart")
public class CartRestController {

    @Autowired
    private CartService cartService;    

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.CREATED)
    public void create(@RequestBody CartDto cartDto) {
        cartService.create(cartDto);
    }
}

2) Esta es la CartService , que es sólo una Interfaz :

public interface CartService {  
    void create(CartDto cartDto); 
}

Esta es la implementación de CartService:

import org.springframework.transaction.annotation.Transactional;

    @Service
    @Transactional
    public class CartServiceImpl implements CartService {   
        @Autowired
        private CartDao cartDao;

        @Override
        public void create(CartDto cartDto) {
            cartDao.create(cartDto);
        }
    }

CartDao es sólo otra interfaz, os muestro sólo su aplicación:

@Repository
public class CartDaoImpl implements CartDao {

    @Autowired 
    private SessionFactory sessionFactory;

    // in this method I save the parent and its children
    @Override
    public void create(CartDto cartDto) {       

        Cart cart = new Cart(); 

        List<CartItem> cartItems = new ArrayList<>();                   

        cartDto.getCartItems().stream().forEach(cartItemDto ->{     
            //here I fill the CartItem objects;     
            CartItem cartItem = new CartItem();         
            ... 
            cartItem.setCart(cart);
            cartItems.add(cartItem);                
        });
        cart.setCartItems(cartItems);

        sessionFactory.getCurrentSession().save(cart);                  
    }
}

Cuando trato de guardar una nueva compra y su cart_item s me sale este error:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/webstore] threw 
exception [Request processing failed; nested exception is 
org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException: Object of 
class     
[com.depasmatte.webstore.domain.CartItem] with identifier [7]: optimistic locking failed; 
nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by 
another transaction (or unsaved-value mapping was incorrect) : 
[com.depasmatte.webstore.domain.CartItem#7]] with root cause
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
 (or unsaved-value mapping was incorrect) : [com.depasmatte.webstore.domain.CartItem#7]

Supongo que el error depende del hecho de que cuando Hibernate tratar de salvar la de un cart_item , la identificación de la compra no existe todavía!

¿Cuál es la forma correcta de guardar un objeto de matriz y su chiquillos en el disparo? Gracias

terraza:

Aquí está la lista de reglas que debe seguir, con el fin de ser capaz de almacenar una entidad matriz junto con sus hijos en una sola toma:

  • tipo cascada PERSISTdebe estar habilitado ( CascadeType.ALLes también muy bien)
  • una relación bidireccional debe ajustarse correctamente en ambos lados . Por ejemplo, los padres contiene todos los niños en su campo de recolección y cada niño tiene una referencia a su padre.
  • la manipulación de datos se lleva a cabo en el ámbito de una transacción. NO SE PERMITE modo de confirmación automática.
  • única entidad matriz debe guardarse manualmente (los niños se guardará automáticamente debido al modo en cascada)

Mapeo de cuestiones:

  • eliminar @Column(name="id")de ambas entidades
  • hacer colocador de cartItems privada . Desde Hibernate está usando su propia implementación de la List, y nunca se debe cambiar directamente a través de la moda
  • inicializar la lista private List<CartItem> cartItems = new ArrayList<>();
  • utilizar @ManyToOne(optional = false)en lugar de nullable = falsedentro de la@JoinColumn
  • prefieren fetch = FetchType.LAZYpara las colecciones
  • es mejor usar ayudante método para establecer relaciones. Por ejemplo, la clase Cartdebe tener un método:

    public void addCartItem(CartItem item){
        cartItems.add(item);
        item.setCart(this);
    }
    

Problemas de diseño:

  • que no es bueno para pasar dtos a la capa DAO. Es mejor hacer la conversión entre las OTD y entidades, incluso por encima de la capa de servicio.
  • que es mucho mejor para evitar tales como el método repetitivo savecon repositorios de datos de Primavera de la APP

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=176962&siteId=1
Recomendado
Clasificación