i have a column in Database with a String, i.e. '{es:title_es,en:title_en}'
So, I need read it as a Map<String,String>, it will be for I18N.
I need the map with the language as key and label as value.
I use Hiberante 3.3.2 and Java 8 and SQL Server.
Is any chance to obtain this map in the EntityClass? This will be usefull because any relationship with this entity will have the correct representation and not a simple string.
And the behavior keep encapsulated.
Table :
OID CODE TITLES
1 XXX '{es:title_es,en:title_en}'
Entity :
#Entity
#Table(name = "TABLE_NAME")
public class EntityClass {
private Long oid;
private String code;
private String titles; ---> i have this but i want private Map<String, String>
#Column(name = "CODE", nullable = false)
public String getCode() {
return code;
}
#Column(name = "TITLES", nullable = false)
public String getTitles() {
return descriptions;
} ----> this work fine, but here i want to get directly the Map,
}```
Related
First sorry this is long but I wanted to provide all information possible.
I am working on a much larger query that will build on this hence the reason I am not taking an easier or other approaches. In addition I can't really change the way we implemented the DB and Domain Objects.
My problem is I can't get a Spring Data JPA Query to work with an Enum. The field is an Enum in the DB as well. Here is the abbreviated code.
The SQL for the 2 tables:
CREATE TABLE my_order (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
creation_date TIMESTAMP NOT NULL,
);
CREATE TYPE ORDER_STATE as ENUM ('new', 'open', 'closed');
CREATE CAST (CHARACTER VARYING AS ORDER_STATE) WITH INOUT AS IMPLICIT;
CREATE TABLE my_order_history (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_date TIMESTAMP NOT NULL,
order_state ORDER_STATE NOT NULL,
order_id INT REFERENCES my_order
);
Here is the corresponding Domain Objects:
#Entity
#Table(name = "my_order")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "creation_date")
private Date creationDate;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<OrderHistory> orderHistories;
}
#Entity
#Table(name = "my_order_history")
public class OrderHistory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "order_date ")
private Date orderDate;
#Column(name = "order_state")
#Convert(converter = OrderStateConverter.class)
private OrderState orderState
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id", nullable = false)
private Order order;
}
Here is the converter:
#Component
#Converter(autoApply = true)
public class OrderStateConverter implement AttributeConverter<OrderState, String> {
#Override
public String convertToDatabaseColumn(OrderState attribute) {
return attribute.getValue;
}
#Override
public OrderState convertToEntityAttribute(String dbData) {
return OrderState.fromValue(dbData);
}
}
Here is the Enum:
public enum OrderState {
NEW("new"), OPEN("open"), CLOSED("closed");
#Getter
private String value;
private OrderState(String value) {
this.value = value;
}
public static OrderState fromValue(String value) {
for (OrderState orderState : values()) {
if (orderState.getValue().equals(value)) {
return orderState;
}
}
return null;
}
}
Here is my Spring Repo. I am putting the 3 ways I have tried and then below I will give you the exceptions I am receiving with each:
#Repository
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
#Query("SELECT o FROM Order o JOIN o.orderHistories oh WHERE oh.orderState = :orderState")
List<Order> getOrdersByOrderState1(#Param("orderState") OrderState orderState);
#Query("SELECT o FROM Order o JOIN o.orderHistories oh WHERE oh.orderState = :orderState")
List<Order> getOrdersByOrderState2(#Param("orderState") String orderState);
#Query("SELECT o FROM Order o JOIN o.orderHistories oh WHERE oh.orderState = :#(#orderState?.getValue())")
List<Order> getOrdersByOrderState3(#Param("orderState") OrderState orderState);
}
For #1 when I provide an OrderState enum I get the following exception:
Caused by: org.postgres.util.PSQLException: ERROR: operator does not exist: order_state = character varying
Hint: No operator matches the given name and argument types. You might need explicit type casts.
For #2 when I provide OrderState.getValue(), which is a String, I get the following exception:
java.jang.IllegalArgumentException: Parameter value [new] did not match expected type [com.testing.enums.OrderState (n/a)]
For #3 when I provide an OrderState enum I get the following exception (same as #2):
java.jang.IllegalArgumentException: Parameter value [new] did not match expected type [com.testing.enums.OrderState (n/a)]
Basically I try to send in the enum and get an error but I also get an error when I try to send in a String. Is there anything I can do? What is exactly happening?
I have this table which I would like to store different values as keys and vales:
#Entity
#Table(name = "wpf_payment_attributes")
public class WpfPaymentAttributes implements Serializable {
private static final long serialVersionUID = -2629784870868584850L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private int id;
#Column(length = 255)
private String name;
#Column(length = 255)
private String global_ley;
#Column(name = "VALUE", columnDefinition = "TEXT", length = 65535)
private String value;
....
}
WpfPaymentAttributes attibutes = new WpfPaymentAttributes();
attibutes.setName("usage");
attibutes.setValue("Test Usage");
attibutes.setGlobal_key(12333);
WpfPaymentAttributes attibutes = new WpfPaymentAttributes();
attibutes.setName("name");
attibutes.setValue("Peter");
attibutes.setGlobal_key(12333);
But how I can get all value with the same global key with one SQL query using JPA? The problem is that I don't know in advance what are the table columns and values.
I need to get this structure:
usage | name
-------------------
Test Usage | Peter
Is this possible with JPA?
This is not possible, since there are some issues that JPA won't be able to help you with:
there could be multiple WpfPaymentAttributes values with the same
global key and name (however, this could be solved by using a
database constraint);
there could be arbitrary values in the name
column, hence you'd have to make sure that they actually map to your expected result structure, there are no unknown "names" etc.
If you don't need a super-generic system, I'd advice you to write a simple mapper, that shouldn't be very complex. Just get all WpfPaymentAttributes by a specific global_key and apply the mapping. For example, here's the structure that you need:
public class Result {
private String usage;
private String name;
// ...
}
And then:
Result result = new Result();
List<WpfPaymentAttributes> attributes = entityManager.createQuery(
// query should be parameterized
"select a from WpfPaymentAttributes a where global_key = 12333"
).getResultList();
for (WpfPaymentAttributes attribute : attributes) {
String value = attribute.getValue();
switch(attribute.getName()) {
case "name":
result.setName(value);
break;
case "usage":
result.setUsage(value);
break;
default:
throw new IllegalStateException();
}
}
return result;
I am using envers in my project to audit data.
Now I want to access changed data with audit query.
My pojo class for table is below
#Entity
#Audited(withModifiedFlag=true)
#Table(name = "INSTRUMENT", uniqueConstraints = #UniqueConstraint(columnNames = "INSTRUMENT_NAME"))
public class Instrument implements java.io.Serializable {
private long instrumentId;
private String instrumentName;
private WorkflowState workflowState;
#Id
#Column(name = "INSTRUMENT_ID", unique = true, nullable = false, precision = 22, scale = 0)
public long getInstrumentId() {
return this.instrumentId;
}
public void setInstrumentId(long instrumentId) {
this.instrumentId = instrumentId;
}
#Column(name = "INSTRUMENT_NAME", unique = true, nullable = false, length = 50)
public String getInstrumentName() {
return this.instrumentName;
}
public void setInstrumentName(String instrumentName) {
this.instrumentName = instrumentName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS", nullable = false)
public WorkflowState getWorkflowState() {
return this.workflowState;
}
public void setWorkflowState(WorkflowState workflowState) {
this.workflowState = workflowState;
}
}
Now I tried to access this with audit query as
AuditQuery query = reader.createQuery().forRevisionsOfEntity(Instrument.class, false, true)
.add(AuditEntity.property("status").hasChanged());
List list= query.getResultList();
So at the time of accessing getResultList() , Its throwing Exception as follows
SqlExceptionHelper: Fail to convert to internal representation
I figured it out, this is because in my db Instrument.status column is as String data Type. While here I am using Join.
So please tell me how to write query to resolve this problem
PROBLEM is How to write Audit Query if my table has foreign key (class property have join dependency).
Join table WorkflowState discription is as follows
public class WorkflowState implements java.io.Serializable {
private BigDecimal stateId;
private Workflow workflow;
private String stateName;
//getters and setters
And it has a join column too i.e "workflow" .
Use workflowState rather than status. The API is based on you specifying the property name and not the column name.
I have a flink project that will be inserting data in a cassandra table as a batch job. I already have a flink stream project where it is writing a pojo to the same cassandra table, but cassandraOutputFormat needs the data as a Tuple (hope that is changed to accept pojos like CassandraSink does at some point). So here is the pojo that I have that:
#Table(keyspace="mykeyspace", name="mytablename")
public class AlphaGroupingObject implements Serializable {
#Column(name = "jobId")
private String jobId;
#Column(name = "datalist")
#Frozen("list<frozen<dataobj>")
private List<CustomDataObj> dataobjs;
#Column(name = "userid")
private String userid;
//Getters and Setters
}
And the dataset of tuple I am making from this pojo:
DataSet<Tuple3<String, List<CustomDataObj>, String>> outputDataSet = listOfAlphaGroupingObject.map(new AlphaGroupingObjectToTuple3Mapper());
And here is the line that triggers the output as well:
outputDataSet.output(new CassandraOutputFormat<>("INSERT INTO mykeyspace.mytablename (jobid, datalist, userid) VALUES (?,?,?);", clusterThatWasBuilt));
Now the issue that I have is when I try to run this, I get this error when it tries to output it to the cassandra table:
Caused by: com.datastax.driver.core.exceptions.CodecNotFoundException:
Codec not found for requested operation: [frozen<mykeyspace.dataobj> <-> flink.custom.data.CustomDataObj]
So I know when it was a pojo, I just had to add the #Frozen annotation to the field, but I don't know how to do that for a tuple. What is the best/proper way to fix this? Or am I doing something unnecessary because there is actually a way to send pojos through the cassandraOutputFormat I just haven't found?
Thanks for any and all help in advance!
EDIT:
Here is the code for the CustomDataObj class too:
#UDT(name="dataobj", keyspace = "mykeyspace")
public class CustomDataObj implements Serializable {
#Field(name = "userid")
private String userId;
#Field(name = "groupid")
private String groupId;
#Field(name = "valuetext")
private String valueText;
#Field(name = "comments")
private String comments;
//Getters and setters
}
EDIT 2
Including the table schema in cassandra that the CustomDataObj is tied to and the mytablename schema.
CREATE TYPE mykeyspace.dataobj (
userid text,
groupid text,
valuetext text,
comments text
);
CREATE TABLE mykeyspace.mytablename (
jobid text,
datalist list<frozen<dataobj>>,
userid text,
PRIMARY KEY (jobid, userid)
);
Add UDT Annotation on CustomDataObj class
#UDT(name = "dataobj")
public class CustomDataObj {
//......
}
Edited
Change jobid Annotation to #Column(name = "jobid") and dataobjs Frozen Annotation to #Frozen
#Table(keyspace="mykeyspace", name="mytablename")
public class AlphaGroupingObject implements Serializable {
#Column(name = "jobid")
private String jobId;
#Column(name = "datalist")
#Frozen
private List<CustomDataObj> dataobjs;
#Column(name = "userid")
private String userid;
//Getters and Setters
}
I believe I have found a better way than having to provide a tuple to the cassandraOutputFormat, but it technically still doesn't answer this question so I won't mark this as the answer. I ended up using cassandra's object mapper so I can just send the pojo to the table. Still need to validate that data got to the table successfully and that everything is working properly with the way it is implemented, but I felt this would help anyone who is facing a similar problem.
Here is the doc that outlines the solution: http://docs.datastax.com/en/developer/java-driver/2.1/manual/object_mapper/using/
I have created some Hibernate mappings with Hibernate 4.3.8.
#Entity
#Table(name = ErrorEntity.TABLE_ID)
#XmlRootElement(name = ErrorEntity.XML_ROOT_TAG)
public class ErrorEntity {
/**
*
*/
private static final long serialVersionUID = 8083918635458543738L;
public static final String TABLE_ID = "Error";
public static final String ERRORCODE = "error_code";
public static final String ENV_ID = "envid";
private Integer error_code;
private Integer envId;
private EnvironmentEntity environment;
public ErrorEntity() {
}
#Id
#Column(name = ErrorEntity.ERRORCODE)
public Integer getError_code() {
return error_code;
}
public void setError_code(Integer errorcode) {
this.error_code = errorcode;
}
#Column(name = ErrorEntity.ENV_ID)
public Integer getEnvId() {
return envId;
}
public void setEnvId(Integer envId) {
this.envId = envId;
}
#ManyToOne
#JoinColumn(name = ErrorEntity.ENV_ID, referencedColumnName = EnvironmentEntity.ENV_ID, insertable = false, updatable = false)
public EnvironmentEntity getEnvironment() {
return environment;
}
public void setEnvironment(EnvironmentEntity environment) {
this.environment = environment;
}
}
As you can see the mapping property ENV_ID is mapped twice.
Thisway I thought I would be able to set the JoinColumn value without querying the database to get the mapped object because I have the JoinColumn value at this point.
The value of ENV_ID is written correctly to the database but if I query this ErrorEntity later and try to get the EnvironmentEntity the reference is null.
ErrorEntity error = (ErrorEntity) criteria.uniqueResult();
System.out.println(error.getEnvironment().getName());
getEnvironment() returns null.
Any ideas how to achieve this?
Edit
It was working like expected to create a new object with the PK set.
Now I have a special situation where it does not work.
I need to reference another object where the joincolumn is not the PK. I know that the value i will join on is unique but there are also some duplicate values i will not join on.
However Hibernate seems to be unable to map this relationship automatically.
ErrorEntity error = new ErrorEntity();
SignalEntity signal = new SignalEntity();
signal.setName(signalName);
error.setSignal(signal);
The problem is that I do not have the signalID (PK) in that situation. The other idea would be to query the db but thats too slow.
I tried to create an composite PK with 3 columns but this breaks the logic at another place.
Is it possible to create two independent PK's?
The ErrorEntity has two ErrorEntity.ENV_ID mappings, which unless you use #MapsId then it's a configuration issue.
You should have an env_id column in EnvironmentEntity table and just the:
#ManyToOne
#JoinColumn(name = ErrorEntity.ENV_ID, referencedColumnName = EnvironmentEntity.ENV_ID, insertable = false, updatable = false)
public EnvironmentEntity getEnvironment() {
return environment;
}
mapping in ErrorEntity.
My suggestion is to remove this:
#Column(name = ErrorEntity.ENV_ID)
public Integer getEnvId() {
return envId;
}
To set the envId directly without querying the database and request the whole EnvironmentEntity, you can do something like this:
errrorEntity.setEnvironment(new EnvironmentEntity());
errrorEntity.getEnvironment().setEnvId(envId);
This is not a JPA standard requirement but Hibernate supports it.