Spring Data JPA and cast to a Postgres custom domain - postgresql

I have the query below:
#Query(value="select t.* from titulos t " +
"where (CAST(:modelosNota AS modelo_nota_fiscal) IS NULL OR t.modelo in (:modelosNota)) order by t.vencimento", nativeQuery = true)
List<Titulo> relatorioTitulosPagarReceber(#Param("modelosNota") String[] modelosNota);
But when it is executed I get the exception below:
org.postgresql.util.PSQLException: ERROR: operator does not exist: modelo_nota_fiscal = bytea
Dica: No operator matches the given name and argument type(s). You might need to add explicit type casts.
I think the message is not very accurate because I already have the type cast to modelo_nota_fiscal which is as custom domain type with a check constraint for some values.
When I run the query in PGAdmin it executes normally:
select t.* from titulos t where (CAST(null AS modelo_nota_fiscal) IS NULL OR t.modelo in (null)) order by t.vencimento;
Or this one that works just fine:
select t.* from titulos t where (CAST('NFe' AS modelo_nota_fiscal) IS NULL OR t.modelo in ('NFe')) order by t.vencimento;
My entity class as requested:
#Data
#EqualsAndHashCode(callSuper = false)
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Entity
#Table(name = "titulos")
public class Titulo extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(length = 30)
private String numero;
#Basic(optional = false)
#Column(nullable = false)
private short natureza;
#Basic(optional = false)
#Column(nullable = false)
private short origem;
#Basic(optional = false)
#Column(nullable = false, precision = 20, scale = 4)
private BigDecimal valor;
#Transient
#Column(name = "valorbaixado")
private BigDecimal valorBaixado;
#Transient
#Column(name = "saldoliquidotitulo")
private BigDecimal saldoLiquidoTitulo;
#Transient
#Column(name = "saldobrutotitulo")
private BigDecimal saldoBrutoTitulo;
#Basic(optional = false)
#Column(nullable = false, precision = 20, scale = 4)
private BigDecimal acrescimo;
#Basic(optional = false)
#Column(nullable = false, precision = 20, scale = 4)
private BigDecimal desconto;
#Basic(optional = false)
#Column(nullable = false, precision = 20, scale = 4)
private BigDecimal juros;
#Basic(optional = false)
#Column(nullable = false, precision = 20, scale = 4)
private BigDecimal multa;
#Basic(optional = false)
#Column(nullable = false)
private LocalDate emissao;
#Basic(optional = false)
#Column(nullable = false)
private LocalDate vencimento;
#Basic(optional = false)
#Column(name = "datamulta")
private LocalDate dataMulta;
#Basic(optional = false)
#Column(nullable = false)
private short situacao;
#Column(length = 2147483647)
private String observacao;
#Column(length = 2147483647)
private String historico;
#Column(length = 20, name = "documentovinculado")
private String documentoVinculado;
#Column(name = "parcela")
private Integer parcela;
#Column(name = "totalparcelas")
private Integer totalParcelas;
#Column(name = "modelo")
private String modelo;
#Column(name = "numerodocumentofiscal")
private String numeroDocumentoFiscal;
#Column(name = "seriedocumentofiscal")
private String serieDocumentoFiscal;
#Column(name = "subseriedocumentofiscal")
private String subserieDocumentoFiscal;
#Column(name = "cfop_codigo")
private String cfopCodigo;
#Column(name = "pis_retido", precision = 20, scale = 2)
private BigDecimal pisRetido;
#Column(name = "cofins_retido ", precision = 20, scale = 2)
private BigDecimal cofinsRetido;
#Column(name = "csll_retido ", precision = 20, scale = 2)
private BigDecimal csllRetido;
#Column(name = "irrf_retido ", precision = 20, scale = 2)
private BigDecimal irrfRetido;
#Column(name = "inss_retido ", precision = 20, scale = 2)
private BigDecimal inssRetido;
#Column(name = "iss_retido ", precision = 20, scale = 2)
private BigDecimal issRetido;
#Column(name = "valor_base ", precision = 20, scale = 2)
private BigDecimal valorBase;
#Column(name = "competencia")
private LocalDate competencia;
#Column(name = "linhadigitavelboleto", length = 44)
private String linhaDigitavelBoleto;
}
Here's my Postgre custom domain type:
CREATE DOMAIN public.modelo_nota_fiscal
AS character varying(3)
COLLATE pg_catalog."default"
CONSTRAINT check_modelo_nota_fiscal CHECK (VALUE::text = 'NFs'::text OR VALUE::text = 'NFe'::text OR VALUE::text = 'CEE'::text OR VALUE::text = 'CFG'::text OR VALUE::text = 'CFA'::text);
ALTER DOMAIN public.modelo_nota_fiscal
OWNER TO postgres;
COMMENT ON DOMAIN public.modelo_nota_fiscal
IS 'MODELO NOTA FISCAL: (NFs) Nota Fiscal de Serviço, (NFe) Nota Fiscal Eletrônica, (CEE) Conta de Energia Elétrica, (CFG) Conta de Fornecimento de Gás, (CFA) Conta de Fornecimento de Água.';
Does anyone know how am I supposed to cast to a custom Postgres domain using Spring Data JPA?

Related

How to filter by faculty name?

I want to implement lazy record loading on a Primefaces DataTable (version 7). I have two entities, one is called Faculties and the other is Careers, which are related. The datatable correctly shows the list of all the races (includes pagination and filtering), the problem I have is that I do not know how to filter the races by the name of a certain faculty, since I do not know how to include the join in the query that I leave then.
Could you guide me on how to solve it please?
Entity Faculties
public class Facultades implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idfacultad")
private Integer idfacultad;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "nombre")
private String nombre;
#Size(max = 20)
#Column(name = "abreviatura")
private String abreviatura;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idfacultad")
private List<Carreras> carrerasList;}
Entity Carreras
public class Carreras implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idcarrera")
private Integer idcarrera;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 150)
#Column(name = "nombre")
private String nombre;
#Basic(optional = false)
#NotNull
#Column(name = "tipo")
private int tipo;
#JoinColumn(name = "idfacultad", referencedColumnName = "idfacultad")
#ManyToOne(optional = false)
private Facultades idfacultad;}
Query findByParams
public List<Carreras> findByParams(int start, int size, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Carreras> criteriaQuery = criteriaBuilder.createQuery(Carreras.class);
Root<Carreras> root = criteriaQuery.from(Carreras.class);
CriteriaQuery<Carreras> select = criteriaQuery.select(root);
Join<Carreras, Facultades> facultad = root.join("idfacultad");
if (sortField != null) {
criteriaQuery.orderBy(sortOrder == SortOrder.DESCENDING ? criteriaBuilder.asc(root.get(sortField)) : criteriaBuilder.desc(root.get(sortField)));
}
if (filters != null && filters.size() > 0) {
List<Predicate> predicados = new ArrayList<>();
filters.entrySet().forEach((entry) -> {
String key = entry.getKey();
Object val = entry.getValue();
if (!(val == null)) {
// Construimos la expresion con los predicados que si existan
Expression<String> expresion = root.get(key).as(String.class);
Predicate predicado = criteriaBuilder.like(criteriaBuilder.lower(expresion), "%" + val.toString().toLowerCase() + "%");
predicados.add(predicado);
}
});
if (predicados.size() > 0) {
criteriaQuery.where(criteriaBuilder.and(predicados.toArray(new Predicate[predicados.size()])));
}
}
// Creamos la consulta
TypedQuery<Carreras> consulta = em.createQuery(select);
consulta.setFirstResult(start);
consulta.setMaxResults(size);
return consulta.getResultList();
}
You need to manually check if the filter key equals the Facultades object, and in that case create a predicate on the joined expression that you have already created:
if (key.equals("Facultad")) {
expresion = facultad.get("nombre").as(String.class);
} else {
expresion = root.get(key).as(String.class);
}

Spring Boot and JpaRepository sort by distance with latitude and longitude params

I have a problem creating a query using the JpaRepository interface. I use the Pageable mechanism. How can I add sort by distance? Geographic parameters available at Event Place. (Latitude, longitude). I would like to add also the ability to limit distance by range. E.g:
"Where distance <: range".
I would like the distance to be returned in the "distance" field, which is #Transient.
EventRepository
#Repository
public interface EventRepository extends JpaRepository<Event, Long> {
public static final String GET_PAGE_QUERY = "WHERE " +
"(:searchTerm is null or e.title like '%:searchTerm%') AND " +
"((:userListId) is null or e.user.id in (:userListId)) AND " +
"((:sportTypeIdList) is null or e.sportType.id in (:sportTypeIdList)) " ;
#Query(value = "SELECT e FROM Event e " + GET_PAGE_QUERY,
countQuery = "SELECT COUNT(e) FROM Event e " + GET_PAGE_QUERY)
Page<Event> getPage(#Param("searchTerm") String searchTerm, #Param("userListId") List<Long> userListId, #Param("sportTypeIdList") List<Long> sportTypeIdList, Pageable pageable);
}
Event
#Getter
#Setter
#Entity
#Table(name = "event")
public class Event {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "event_seq")
#SequenceGenerator(name = "event_seq", sequenceName = "event_seq", allocationSize = 1)
private Long id;
#Column(name = "TITLE", length = 50, nullable = false)
#NotNull
#Size(min = 4, max = 50)
private String title;
#Column(name = "DESCRIPTION", length = 500, nullable = false)
#NotNull
#Size(min = 4, max = 500)
private String description;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
private SportType sportType;
#OneToOne(fetch = FetchType.EAGER, optional = false)
private EventPlace place;
#ManyToOne(optional = false)
private User user;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
#Column(name = "CREATE_DATE", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull
private Date createDate = new Date();
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
#Column(name = "START_DATE", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull
private Date startDate;
#Column(name = "STATUS", nullable = false)
#NotNull
#Enumerated(EnumType.STRING)
private EventStatus status = EventStatus.ACTIVE;
#Transient
private double distance;
}
EventPlace
#Getter
#Setter
#Entity
public class EventPlace {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "event_place_seq")
#SequenceGenerator(name = "event_place_seq", sequenceName = "event_place_seq", allocationSize = 1)
private Long id;
#Column(name = "NAME", length = 50, nullable = false)
#NotNull
#Size(min = 4, max = 50)
private String name;
#Column(name = "CITY", length = 50, nullable = false)
#NotNull
#Size(min = 4, max = 50)
private String city;
#Column(name = "STREET", length = 50, nullable = false)
#NotNull
#Size(min = 4, max = 50)
private String street;
#Column(name = "ZIP_CODE", length = 50, nullable = false)
#NotNull
#Size(min = 4, max = 50)
private String zipCode;
#Column(name = "DESCRIPTION", length = 500, nullable = false)
#NotNull
#Size(min = 4, max = 500)
private String description;
#Column(name = "LATITUDE", nullable = false)
#NotNull
private Double latitude;
#Column(name = "LONGITUDE", nullable = false)
#NotNull
private Double longitude;
}

Entity mapping issues

I am pretty new to java and data entities and I am getting the, "Exception Description: An incompatible mapping has been encountered between [class com.store.Product] and [class com.store.Cart]." error and not sure why (obviously).
My mappings are as follows:
Product.java
#Basic(optional = false)
#NotNull
#Column(name = "P_QTY")
private Integer pQty;
#Column(name = "P_PRICE")
private BigDecimal pPrice;
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "P_ID")
private String pId;
#Size(max = 10)
#Column(name = "P_NAME")
private String pName;
#Size(max = 20)
#Column(name = "P_DESC")
private String pDesc;
#OneToMany(mappedBy = "pId")
Cart.java
#Id
#Basic(optional = false)
#NotNull
#Column(name = "C_ID")
private String cId;
#Basic(optional = false)
#NotNull
#Column(name = "C_QTY")
private Integer cQty;
#Column(name = "C_PRICE")
private Double cPrice;
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 10)
#JoinColumn(name = "P_ID", referencedColumnName = "P_ID")
#ManyToOne
private String pId;
Any ideas? Like I said, I'm new to data entities and have done enough reading to confuse myself at this point so I apologize for any and all idiocy on my part.
Thanks in advance.

The abstract schema type is unknown

I'm using Spring 3.2.3, JPA 2.1, JUnit 4.11. I'm trying to run a junit test and I keep getting the abstract schema type is unknown error. Here is my entity (truncated for space, it has all the getters and setters):
#Entity
#Table(name = "WEB_PROFILES")
public class TestWebProfile implements Serializable {
private static final long serialVersionUID = 1L;
#Transient
private String forward;
#Column(name = "ACCESS_FLAG")
private String accessFlag;
#Temporal(TemporalType.DATE)
#Column(name = "ACCESS_FLAG_UPD_DATE")
private Date accessFlagUpdDate;
#Column(name = "ACCESS_RESET_INTERVAL")
private BigDecimal accessResetInterval;
#Column(name = "ACCOUNT_TYPE")
private String accountType;
#Column(name = "CREATED_BY")
private String createdBy;
#Column(name = "E_MAIL")
private String eMail;
#Column(name = "FAILED_LOGIN_ATTEMPTS")
private BigDecimal failedLoginAttempts;
#Column(name = "FIRST_NAME")
private String firstName;
#Temporal(TemporalType.DATE)
#Column(name = "FROI_ACCESS_APPROVE_DENY_DATE")
private Date froiAccessApproveDenyDate;
#Column(name = "FROI_ACCESS_APPROVED_FLAG")
private String froiAccessApprovedFlag;
#Column(name = "FROI_ACCESS_REQUESTED")
private String froiAccessRequested;
#Column(name = "FROI_APPROVED_BY")
private String froiApprovedBy;
#Temporal(TemporalType.DATE)
#Column(name = "FROI_CONFIRM_EMAIL_SENT_DATE")
private Date froiConfirmEmailSentDate;
#Temporal(TemporalType.DATE)
#Column(name = "FROI_LETTER_SENT_DATE")
private Date froiLetterSentDate;
#Column(name = "LAST_LOGON_ADDR")
private String lastLogonAddr;
#Temporal(TemporalType.DATE)
#Column(name = "LAST_LOGON_DATE")
private Date lastLogonDate;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "LAST_UPDATED_BY")
private String lastUpdatedBy;
#Column(name = "LAST_UPDATED_BY_NAME")
private String lastUpdatedByName;
#Column(name = "LAST_UPDATED_BY_SU_ID")
private BigDecimal lastUpdatedBySuId;
#Temporal(TemporalType.DATE)
#Column(name = "MAIL_SENT_DATE")
private Date mailSentDate;
#Temporal(TemporalType.DATE)
#Column(name = "MAINT_DATE")
private Date maintDate;
#Temporal(TemporalType.DATE)
#Column(name = "NEW_PIN_REQ_DATE")
private Date newPinReqDate;
#Column(name = "PASSWORD")
private String password;
#Transient
private String newPassword;
#Temporal(TemporalType.DATE)
#Column(name = "PASSWORD_UPD_DATE")
private Date passwordUpdDate;
#Column(name = "PHONE")
private String phone;
#Column(name = "PIN")
private String pin;
#Column(name = "POLICY_NUM")
private BigDecimal policyNo;
#Column(name = "PROFILE_CLASS_CODE")
private String profileClassCode;
#Temporal(TemporalType.DATE)
#Column(name = "PROFILE_REQ_DATE")
private Date profileReqDate;
#Temporal(TemporalType.DATE)
#Column(name = "PROFILE_UPDATE_DATE")
private Date profileUpdateDate;
#Column(name = "REMOTE_ADDR")
private String remoteAddr;
#Column(name = "SESSIONID")
private String sessionid;
#Column(name = "SUBSCRIBER_FLAG")
private String subscriberFlag;
#Column(name = "USER_ID")
private BigDecimal userId;
#Id
#Column(name = "USER_NO")
private BigDecimal userNo;
#Column(name = "USERNAME")
private String username;
My JUnit test:
#Test
public void testGetWebProfileByUsername() {
TestWebProfile wp = sso.getWebProfile("MARLENE");
System.out.println("name :" + wp.getFirstName());
System.out.println("last name :" + wp.getLastName());
}
My DAO implementation:
#Override
public TestWebProfile getWebProfile(String username) {
String sqlString = "select w from TestWebProfile w where w.username =:username";
return (TestWebProfile) getEntityManager()
.createQuery(sqlString, TestWebProfile.class)
.setParameter("username", username).getSingleResult();
}
After Googling for the past hour, the only culprit I found that seem to make sense was not having the #Id and #Column annotations, but I have those on the userNo variable. Any help that can be provided would be greatly appreciated!
Have a look at this. It gives some suggesstion for the same case http://java.dzone.com/tips/the-nasty-jpa-unknown-abstract
If you are using Java SE you have to add the fully qualified name of your entity class in persistence.xml, like so
<persistence-unit ...>
<class>your.custom.package.TestWebProfile</class>
</persistence-unit>
Omitting the package part may lead to your error.
Try adding inside your persistence-unit tag as follows:
<exclude-unlisted-classes>false</exclude-unlisted-classes>
For some reason in my case although I was listing all the classes inside my persistence unit using fully qualified names, eclipseLink didn't recognize them. Once added that line, it just works.
I was using:
Java SE 8
Maven Project
EclipseLink (Local not an application server)
Netbeans

Insert object with composite primary key

I need help with this. With code is more clear, this is my function to persist:
public String finalizarCompra() {
Pedido pedido = new Pedido();
pedido.setEstado("almacen");
pedido.setFechaVenta(new Date());
pedido.setIdUsuario(loginBean.getUsuario());
Producto p;
Integer i;
DetPedido detPedido;
List<DetPedido> lista = new ArrayList<>();
for (Map.Entry e : productos.entrySet()) {
detPedido = new DetPedido();
p = (Producto) e.getKey();
i = (Integer) e.getValue();
detPedido.setProducto(p);
detPedido.setCantidad(i);
detPedido.setPrecioUnidad(p.getPrecioUnidad());
detPedido.setPedido(pedido);
lista.add(detPedido);
detPedidoBean.insert(detPedido);
}
pedido.setDetPedidoCollection(lista);
pedidoBean.insert(pedido);
return "";
}
This is my Pedido Entity:
#Entity
public class Pedido implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "FECHA_VENTA")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaVenta;
#Column(name = "FECHA_ENVIO")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaEnvio;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "ESTADO")
private String estado;
#JoinColumn(name = "ID_USUARIO", referencedColumnName = "ID_USUARIO")
#ManyToOne(optional = false)
private Usuario idUsuario;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "pedido")
private Collection<DetPedido> detPedidoCollection;
// Getters and Setters //
This is my DetPedido Entity:
#Entity
public class DetPedido implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected DetPedidoPK detPedidoPK;
#Basic(optional = false)
#NotNull
#Column(name = "CANTIDAD")
private Integer cantidad;
#Basic(optional = false)
#NotNull
#Column(name = "PRECIO_UNIDAD")
private Double precioUnidad;
#JoinColumn(name = "ID_PRODUCTO", referencedColumnName = "ID_PRODUCTO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Producto producto;
#JoinColumn(name = "ID_PEDIDO", referencedColumnName = "ID_PEDIDO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Pedido pedido;
// Getters and Setters //
And this is my DetPedidoPK:
#Embeddable
public class DetPedidoPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "ID_PRODUCTO")
private Integer idProducto;
// Getters and Setters //
The Entities ara generated automatically from the Database, also DetPedidoPK, and now I don't know how to save a Pedido. I tried with the code above, but it doesn't work.
Can anybody help me?
Greetings.
If you are using JPA 1.0 and this entity model, then you will need to persist and flush both Producto and Pedido instances to have their IDs assigned before you can persist the DetPedido instance that will reference them. Once that is done, you will need to manually set the id values in DetPedido's DetPedidoPK instance so that they match the referenced Producto and DetPedido key values. You cannot insert DetPedido without the DetPedidoPK values having been set.
JPA 2.0 supports derived IDs, which allows marking the relationship as either #ID or #MapsId, indicating that the ID values should be pulled from the joincolumn associated to the relationship. In this case, it would become:
#ManyToOne(optional = false)
#MapsId("idProducto")
private Producto producto;
#ManyToOne(optional = false)
#MapsId("idPedido")
private Pedido pedido;
If you wanted, you could do away with the embeddable within DetPedido and just mark the relationships as the #Id, and because it is composite you would use the DetPedidoPK as the PK class.