I have the object Usuario, I want to update it into the database, but it only save the changes in some attributtes.
#Entity
public class Usuario {
#Id
String nombre_Usuario;
String contrasena;
String estado;
#OneToOne(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#PrimaryKeyJoinColumn
Posicion miPosicion;
}
#Entity
public class Posicion {
#Id
int id;
float latitud;
float longitud;
float altura;
public Posicion() {
id = (int) Math.floor(Math.random()*1000);
latitud = longitud = altura = 0;
}
public Posicion(float alatitud, float alongitud, float aaltura) {
id = (int) Math.floor(Math.random()*1000);
latitud = alatitud;
longitud = alongitud;
altura = aaltura;
}
I'm working with a restfull service and when I want to change the object I do:
Usuario u = new Usuario();
u = todoService.obtenerUsuarioBusqueda("user_name"); //Here I get the object I want to change
u.setEstado("New Estado");
u.setmiPosicion(new Posicion(10,10,10));
todoService.saveUsuario(u);
public String saveUsuario(Usuario u){
try{
entityManager.merge(u);
}catch(Exception e){
return "false"+e.getMessage();
}
return "true";
}
I make this for update the object in the database. And when I make a find(u), the estado is "New Estado", but when I try to get the attribute miPosicion it is null.
Just after making u.setmiPosicion(), if I make u.getmiPosicion() it is correct, the Posicion I have set. But when I make it from the object from find(u) it is null.
Related
I am trying exchange data stored on objects from a c++/qt project to java/spring using websockets and json. the communication via websockets are working fine, but in the java/spring the data arrives as null.
in the c++ class, i have something like that:
QString Usuario::toString() {
QString json = "{'email': "+email+"}";
QJsonDocument document = QJsonDocument::fromJson(json.toUtf8());
QByteArray prettyPrintedJson = document.toJson(QJsonDocument::Indented);
return prettyPrintedJson;
}
for classes like that:
usuario.h
class Usuario
{
private:
QString email;
public:
Usuario();
Usuario(QString email);
QString getEmail();
void setEmail(QString email);
QString toString();
};
registro.h
class Registro
{
private:
QString token;
Usuario usuario;
Produto produto;
Maquina maquina;
public:
Registro();
Registro(QString token, Usuario usuario, Produto produto, Maquina maquina);
Registro(Usuario usuario, Produto produto, Maquina maquina);
QString getToken();
void setToken(QString token);
Usuario getUsuario();
void setUsuario(Usuario usuario);
Produto getProduto();
void setProduto(Produto produto);
Maquina getMaquina();
void setMaquina(Maquina maquina);
QString toString();
};
in the java project, I have something like this:
#Component
public class CheckRegistro extends TextWebSocketHandler {
...
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException {
Registro value = new Gson().fromJson(message.getPayload(), Registro.class);
System.out.println("registro -> " + value);
String email_usuario = value.getUsuario().getEmail();
Usuario usuario = usuarioServ.findBy("email", email_usuario);
String nome_produto = value.getProduto().getNome();
Produto produto = produtoServ.findBy("nome", nome_produto);
Cliente cliente = clienteServ.findBy("usuario", usuario);
if(cliente.produtosComprados().contains(produto))
value = registroServ.findBy("produto", produto);
String result = new Gson().toJson(value);
session.sendMessage(new TextMessage(result));
}
...
}
and classes like that:
usuario.java
#Entity
public class Usuario extends Model implements UserDetails {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column
private String username;
#Column
private String password;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
...
}
registro.java
#Entity
public class Registro extends Model{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column
private String token;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Usuario usuario;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Produto produto;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Maquina maquina;
...
}
(for the record, some classes, like usuario have more fields in java than c++; others, like registro have the same fields either on the c++ side or in the java side).
someone can hint me what's wrong here? I know there is some libraries that can serialize the c++ object into json automatically, but I dunno if it's possible do that without add a third-party component to my project, just finding the right format for the string sent to the java socket.
update
I change the toString method in the c++ side to something like that:
QString Registro::toString() {
QJsonObject json{
{ "token", token },
{ "usuario", usuario.toString() },
{ "produto", produto.toString() },
{ "maquina", maquina.toString() }
};
QJsonDocument jsonDoc;
jsonDoc.setObject(json);
QByteArray prettyPrintedJson = jsonDoc.toJson(QJsonDocument::Indented);
return prettyPrintedJson;
}
and now, in the java side, the json string is printed like that:
"registro": "{\n \"maquina\": \"{\\n \\\"cpuArch\\\": \\\"x86_64\\\",\\n \\\"hostName\\\": \\\"DESKTOP-7GAPC4K\\\",\\n \\\"kernelType\\\": \\\"windows\\\",\\n \\\"kernelVersion\\\": \\\"10\\\",\\n \\\"productName\\\": \\\"Windows 10 Version 1909\\\",\\n \\\"ram\\\": \\\"RAM: 16030 MB\\\",\\n \\\"uniqueId\\\": \\\"c69d8cc7-8e66-4ea3-964a-792b2c2a6f80\\\"\\n}\\n\",\n \"produto\": \"{\\n \\\"nome\\\": \\\"prod1\\\"\\n}\\n\",\n \"token\": \"\",\n \"usuario\": \"{\\n \\\"email\\\": \\\"klebermo#gmail.com\\\"\\n}\\n\"\n}\n"
}
update 2
I change the method toString in the c++ side to something like that:
QString Registro::toString() {
return "{ \"token\": \""+token+"\", \"usuario\": "+usuario.toString()+", \"produto\": "+produto.toString()+", \"maquina\": "+maquina.toString()+" }";
}
and now in the java side I get a valid json, but here:
Registro value = new Gson().fromJson(message.getPayload(), Registro.class);
String email_usuario = value.getUsuario().getEmail();
Usuario usuario = usuarioServ.findBy("email", email_usuario);
String nome_produto = value.getProduto().getNome();
Produto produto = produtoServ.findBy("nome", nome_produto);
I am geting a NullPointerException for value.getUsuario().getEmail(). I really need send a class from the c++ side with all the fields from the java class? Is there any way to allow me send only the class with fields needed for this query? Or this is not the problem?
json in Usuario::toString is not valid JSON. QJsonDocument::fromJson returns null when parsing fails.
Assuming email is not quoted you need:
QString json = "{\"email\": \""+email+"\"}";
Alternatively, safer and simpler would be to use the JSON API:
QJsonObject json{
{ "email", email }
};
QJsonDocument document = QJsonDocument::fromJson(json);
QByteArray prettyPrintedJson = document.toJson(QJsonDocument::Indented);
Im having a trouble with my code. i have a view jsp where i can view all items.
When i try to search for a name. It will loop or have a redundancy. I dont know why. looks like this.
BTW i have two tables and a foreign key product[pid] to stock[pid]
public class Product {
#Id
#Column(name="p_id")
private String pid;
#Column(name="p_name")
private String p_name;
#Column(name="c_name")
private String c_name;
#Column(name="b_name")
private String b_name;
//SETTERS & GETTERS
public class Stock {
#Id
#Column(name="s_id")
private int sid;
#Column(name="p_id")
private String pid;
#Column(name="s_quantity")
private String squantity;
#Column(name="s_price")
private String sprice;
#Column(name="s_cost")
private String cost;
//SETTERS AND GETTERS
#Controller
#RequestMapping(method = RequestMethod.POST, value = "/searchItem")
public String searchItem(HttpServletRequest request, ModelMap map,
#RequestParam(value = "page", required = false) Integer page,
#RequestParam(value = "size", required = false) Integer size ) {
String searchProductName = request.getParameter("productName");
String cat = request.getParameter("category");
String bran = request.getParameter("brand");
Product searchProduct = new Product();
searchProduct.setP_name(searchProductName);
searchProduct.setC_name(cat);
searchProduct.setB_name(bran);
int pageSize = (size != null && size != 0) ? size : 25;
int firstResultIndex = (page != null && page > 0) ? (page - 1) * pageSize : 0;
List<Product> productList = catService.getUsers(searchProduct, firstResultIndex, pageSize);
map.addAttribute("productList", productList);
List<Category> cList = catService.getCat();
map.addAttribute("cList", cList);
List<Brand> bList = catService.getBrand();
map.addAttribute("bList", bList);
return "new/list";
}
#DaoImpl
#SuppressWarnings("unchecked")
#Override
public List<Product> getUsers(Product searchProduct, int startPage, int maxResults) {
EntityManager entityManager = transactionManager.getEntityManagerFactory().createEntityManager();
Session session = entityManager.unwrap(Session.class);
SQLQuery query = session.createSQLQuery("FROM product,stock");
boolean paramExists = false;
if (!StringUtility.isStringNullOrEmpty(searchProduct.getC_name())&&!StringUtility.isStringNullOrEmpty(searchProduct.getB_name())) {
//sqlQuerySB.append(" product.c_name LIKE :category AND product.b_name LIKE :brand");
query = session.createSQLQuery("FROM product,stock WHERE product.c_name LIKE :category AND product.b_name LIKE :brand");
paramExists = true;
}
if (!StringUtility.isStringNullOrEmpty(searchProduct.getP_name())) {
query = session.createSQLQuery("SELECT product.p_name,product.c_name,product.b_name,stock.s_quantity,stock.s_price,stock.s_cost FROM product,stock WHERE product.p_name LIKE :productName");
query.setParameter("productName", "%" + searchProduct.getP_name() + "%");
paramExists = true;
}
if (!StringUtility.isStringNullOrEmpty(searchProduct.getC_name())) {
query = session.createSQLQuery("SELECT product.p_name,product.c_name,product.b_name,stock.s_quantity,stock.s_price,stock.s_cost FROM product,stock WHERE product.c_name LIKE :category ");
query.setParameter("category", "" + searchProduct.getC_name() + "");
paramExists = true;
}
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List<Product> productList = query.list();
if (entityManager.isOpen())
entityManager.close();
return productList;
}
maybe there is a big problem in my DAOimpl on how i query two tables..
need some help/advice. ty.
You are not specifying the join criteria between product and stock:
SELECT
product.p_name,
product.c_name,
product.b_name,
stock.s_quantity,
stock.s_price,
stock.s_cost
FROM product, stock
WHERE product.p_name LIKE :productName
In this case it will return one row for each for each combination of product (with the name) and stock (full table since it does not have any criteria).
Try to specify the join criteria:
SELECT
product.p_name,
product.c_name,
product.b_name,
stock.s_quantity,
stock.s_price,
stock.s_cost
FROM product, stock
WHERE
product.pid = stock.pid
product.p_name LIKE :productName
Well, I work with JSF + Hibernate/JPA, I have the following code:
public void loadAddressByZipCode(ActionEvent event){
Address address = boDefault.findByNamedQuery(Address.FindByZipCode, 'zipCode', bean.getAddress().getZipCode());
if (address == null){
//This zip code not exists in db
}else{
bean.setAddress(address);
}
}
This method above is called in every "onBlur" in inputText component in XHTML page, this inputText have the property value like this: "#{addressMB.bean.address.zipCode}"
So, when user (in XHTML page) type a new Zip Code this value is setted in "bean.getAddress().setZipCode()" and i search for this value in Database. But debugging my application i discovered that when i do "bean.getAddress().getZipCode()" the Hibernate launch a "update address set ..." in my DataBase. How can i prevent this and why this happens ?
EDIT 1:
This is my real method implemented
public void carregarLogradouroByCep(AjaxBehaviorEvent event) {
List listReturn = getBoPadrao().findByNamedQuery(
Logradouro.FIND_BY_CEP,
new NamedParams("cep", bean.getLogradouro().getCep()));
if (listReturn.size() > 0) {
Logradouro logradouro = (Logradouro) listReturn.get(0);
bean.setLogradouro(logradouro);
}else{
bean.setLogradouro(new Logradouro());
}
}
This is my component with onblur event:
<p:inputText value="#{enderecoMB.bean.logradouro.cep}" id="cep"
required="true" requiredMessage="O CEP é obrigatório">
<p:ajax event="blur"
listener="#{enderecoMB.carregarLogradouroByCep}"
update=":formManterEndereco:logradouro, :formManterEndereco:cidade, :formManterEndereco:estado,
:formManterEndereco:bairro" />
</p:inputText>
I have a "BasicDAOImpl" that make all operations in database, so tried do it in my entityManager:
#PostConstruct
private void init(){
entityManager.setFlushMode(FlushModeType.COMMIT);
}
But "update automatically" continue.
EDIT 2: My FIND_BY_CEP query
"SELECT c FROM Endereco c JOIN FETCH c.tipoEndereco JOIN FETCH c.logradouro"
EDit 3: My Entities
Endereco.java
#Entity
#NamedQueries(value = { #NamedQuery(name = "Endereco.findAllCompleto", query = "SELECT c FROM Endereco c "
+ "JOIN FETCH c.tipoEndereco " + "JOIN FETCH c.logradouro") })
#Table(name = "endereco")
public class Endereco extends AbstractBean {
/**
*
*/
private static final long serialVersionUID = 5239354646908722819L;
public Endereco(){
logradouro = new Logradouro();
}
#Transient
public static final String FIND_ALL_COMPLETO = "Endereco.findAllCompleto";
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_tipo_endereco")
private TipoEndereco tipoEndereco;
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
#JoinColumn(name = "id_logradouro")
private Logradouro logradouro;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_pessoa")
private Pessoa pessoa;
#Column
private String numero;
#Column
private String complemento;
public Logradouro getLogradouro() {
return logradouro;
}
public void setLogradouro(Logradouro logradouro) {
this.logradouro = logradouro;
}
public TipoEndereco getTipoEndereco() {
return tipoEndereco;
}
public void setTipoEndereco(TipoEndereco tipoEndereco) {
this.tipoEndereco = tipoEndereco;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
public String getComplemento() {
return complemento;
}
public void setComplemento(String complemento) {
this.complemento = complemento;
}
public Pessoa getPessoa() {
return pessoa;
}
public void setPessoa(Pessoa pessoa) {
this.pessoa = pessoa;
}
}
Logradouro.java
#Entity
#NamedQueries(value = { #NamedQuery(name = "Logradouro.findByCep", query = "SELECT c FROM Logradouro c "
+ "JOIN FETCH c.bairro "
+ "JOIN FETCH c.cidade "
+ "WHERE c.cep = :cep "
+ "ORDER BY c.logradouro") })
#Table(name = "logradouro")
public class Logradouro extends AbstractBean {
public Logradouro(){
this.cidade = new Cidade();
this.bairro = new Bairro();
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Transient
public static final String FIND_BY_CEP = "Logradouro.findByCep";
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
#JoinColumn(name = "id_cidade")
private Cidade cidade;
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
#JoinColumn(name = "id_bairro")
private Bairro bairro;
#Column
private String cep;
#Column
private String logradouro;
public Cidade getCidade() {
return cidade;
}
public void setCidade(Cidade cidade) {
this.cidade = cidade;
}
public Bairro getBairro() {
return bairro;
}
public void setBairro(Bairro bairro) {
this.bairro = bairro;
}
public String getCep() {
return cep;
}
public void setCep(String cep) {
this.cep = cep;
}
public String getLogradouro() {
return logradouro;
}
public void setLogradouro(String logradouro) {
this.logradouro = logradouro;
}
}
Hibernate uses an entitymanager to do automatic handling of your entities by default. Your bean is one such entity so whenever the entitymanager feels it's time to flush to the database it does so. If you want to flush manually, you'll want to have a look at such a construction:
entityManager.setFlushMode(javax.persistence.FlushModeType.MANUAL);
I think that you misuse Hibernate. The main idea of ORM that is allows you to write code, ignoring that fact, that something goes into database. Your domain model must be completetly testable without any database. ORM is not abstraction to manage with relation database, it is abstraction for your object model. If you need to explicitly do inserts and updates, you better use some active record implementation or look at lightweight mapper like MyBatis.
And why you want to prevent database update? Property is changed, right? So let Hibernate decide, whether and when its new value must be written to database.
I'm using Hibernate + HSQL on JBOSS server, I need to saveOrUpdate() an Object which has an ID represented by another class:
public class RideId implements java.io.Serializable {
private int beginPop;
private int endPop;
private String requestUser;
public RideId() {
}
public RideId(int beginPop, int endPop, String requestUser) {
this.beginPop = beginPop;
this.endPop = endPop;
this.requestUser = requestUser;
}
...
so, "RideID" is the ID of the entity "Ride"
public class Ride implements java.io.Serializable {
private RideId id;
private User userByRequestUser;
private User userByAcceptUser;
private Pop pop;
private Boolean rideStatus;
public Ride() {
}
public Ride(RideId id, User userByRequestUser, Pop pop) {
this.id = id;
this.userByRequestUser = userByRequestUser;
this.pop = pop;
}
public Ride(RideId id, User userByRequestUser, User userByAcceptUser,
Pop pop, Boolean rideStatus) {
this.id = id;
this.userByRequestUser = userByRequestUser;
this.userByAcceptUser = userByAcceptUser;
this.pop = pop;
this.rideStatus = rideStatus;
}
...
how can I saveOrUpdate() a new Object of type Ride?
Thanks everyone and sorry for my english!
It's simple. You need to create first a new RideId, assign it to a new Ride and call saveOrUpdate with the Ride.
RideId id = new RideId(1, 2, "someuser");
Ride ride = new Ride(id, ...);
session.saveOrUpdate(ride);
Calling javax.persistence.criteria.Path.get(String name) fails for the simple class hierarchy detailed below. The call succeeds if #IdClass and 2nd id field (i.e. id2) are removed. Anyone know why this is so. Does this mean it is not possible to query on a single id field where that id field forms part of a composite key?
failing call is: Path<Object> path = entity.get(name);
private static final EntityManager em;
private final CriteriaBuilder cb = em.getCriteriaBuilder();
private final CriteriaQuery<Y> query = cb.createQuery(Y.class);
private final Root<Y> entity = query.from(Y.class);
static {
Map<String, Object> properties = new HashMap<String, Object>();
// initialise properties appropriately
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("test", properties);
em = emf.createEntityManager();
}
interface PK {
Object getPK();
}
public static class YPK implements Serializable {
int id;
int id2;
YPK(int id, int id2) { }
// Override hashCode() and equals() appropriately
}
#IdClass(YPK.class)
#Entity
public static class Y implements Serializable, PK {
#Id
int id;
#Id
int id2;
protected Y() { }
public Y(int id) {
this.id = id;
}
#Override
public Object getPK() {
return id;
}
}
#Test
public void simpleTest() {
List<Y> yy = new ArrayList<Y>();
Y yX1 = new Y(5);
yy.add(yX1);
Y yX2 = new Y(6);
yy.add(yX2);
saveItems(yy);
String name = "id";
Path<Object> path = entity.get(name);
Predicate restriction = cb.conjunction();
restriction = cb.and(restriction, cb.and(new Predicate[]{cb.equal(path, 5)}));
TypedQuery<Y> tq = em.createQuery(this.query);
Y result = null;
try {
result = tq.getSingleResult();
} catch (NoResultException e) {
}
assertNotNull(result);
}
To access fields that are members of the IdClass you need to use metamodel.
I suggest to go with static metamodel, because it is cleaner and kind of type safe. You can generate it with the tools or write it by yourself. For class Y it will be something like:
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
#StaticMetamodel(Y.class)
public abstract class Y_ {
public static volatile SingularAttribute<Y, Integer> id;
public static volatile SingularAttribute<Y, Integer> id2;
// + similar definitions for other fields:
// <TYPE_OF_ENTITY, TYPE_OF_ATTRIBUTE> NAME_OF_FIELD_IN_ENTITY
}
Then you can use IdClass fields in criteria query:
Path<Integer> pathToId = entity.get(Entity2_.id);
Path<Integer> pathToId2 = entity.get(Entity2_.id2);
If you don't want to generate static metamodel, then there is still following rather bad way to access attributes of id:
//find set of all attribute that form id
Metamodel mm = em.getMetamodel();
EntityType et = mm.entity(Y.class);
Set<SingularAttribute> idAttributes = et.getIdClassAttributes();
SingularAttribute idAttribute = null;
//and pick out right one from [id, id2]
for (SingularAttribute candidate : idAttributes) {
if (candidate.getName().equals("id")) {
idAttribute = candidate;
break;
}
}
Path<Integer> path = entity.get(idAttribute);