I am working on an issue using Java where i have to restrict specific string to store in DB.Example : "NAM" or "nam"
if some data "Vietnam" (Contains "nam") is coming to store in any column, i have to restrict and give some kind of error or notification.
This is easy if we are working one object but if there are multiple tables in the DB and we need to check each and every column data before storing that is painful. i am looking for some generic code that can work on any object.
You could try using Hibernate's check annotations:
#Entity
#Check(constraints = "col1 <> 'Vietnam' AND col2 <> 'Vietnam'")
public class YourEntity {
#Column(name = "col1")
private String col1;
#Column(name = "col2")
private String col2;
...
}
Hibernate should then throw an exception should any entity arrive with a field having the value Vietnam.
If you can't use Hibernate check annotations, a general solution which might work here on the database level would be a check constraint:
ALTER TABLE yourTable
ADD CONSTRAINT cntry_cnstr CHECK (col1 <> 'Vietnam' AND col2 <> 'Vietnam' AND ...);
Attempting to insert a new record where a column contains Vietnam, or attempting to update an existing record's column to Vietnam would then trigger an exception which you could handle in Java.
Related
I'm trying to learn JPA/Hibernate and I'm real green in this field. I tend to usually veer off and try things without knowing much about the API. So I decided to create a simple entity that retrieves information from multiple tables see this is easily implementable with JPA. The reason behind this is, if, hypothetically, the involving tables each has a few hundred columns and we only have a business need to retrieve a very few data, and we only need to focus on retrieval rather than inserts/updates/deletions, I would assume it is best to only retrieve the entire entity (specially if multiple rows need to be returned) then join them across other entities to derive a few columns.
I started up with two simple tables:
EMPLOYEES
EMPLOYEE_ID, EMAIL, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, etc...
DEPARTMENTS
DEPARTMENT_ID, DEPARTMENT_NAME, MANAGER_ID, etc...
I want my entity to retrieve only the following columns solely based on EMPLOYEES.EMPLOYEE_ID:
EMPLOYEES.EMPLOYEE_ID
EMPLOYEES.MANAGER_ID
EMPLOYEES.DEPARTMENT_ID
DEPARTMENT.DEPARTMENT_NAME
One thing to notice here is that EMPLOYEES.MANAGER_ID is a self-referencing foreign key to EMPLOYEES.EMPLOYEE_ID.
I might create the following...
#SecondaryTable(name="DEPARTMENTS",
pkJoinColumns=#PrimaryKeyJoinColumn(name="managerId",referencedColumnName="employeeId")
)
#Table(name="EMPLOYEES")
#Entity
public class EmployeesDepartment {
#Id
private String employeeId;
private String managerId;
private String email;
private int departmentId;
#Column(name="DEPARTMENT_NAME",table="DEPARTMENTS")
private String departmentDesc;
// Setters and getters
}
Obviously this doesn't give us the correct answer due to the fact that the join between the secondary table (DEPARTMENTS) occurs between its MANAGER_ID and EMPLOYEES.EMPLOYEE_ID, rather than DEPARTMENTS.MANAGER_ID = EMPLOYEES.MANAGER_ID.
I cannot replace referencedColumnName="employeeId" with referencedColumnName="managerId" as managerId of #Entity EmployeesDepartment is not a primary key of EMPLOYEES.
And I can't do the following:
#OneToOne
#JoinColumn(name="managerId",table="DEPARTMENTS",referencedColumnName="employeeId")
private String managerId;
My question is, how can I make my join to be on DEPARTMENTS.MANAGER_ID = EMPLOYEES.MANAGER_ID while the WHERE clause of the query is based on EMPLOYEES.EMPLOYEE.ID? In other word, how can I have the entity that is mapped to the following query:
SELECT
E.EMPLOYEE_ID,
E.MANAGER_ID,
E.DEPARTMENT_ID,
D.DEPARTMENT_NAME
FROM EMPLOYEES E LEFT OUTER JOIN DEPARTMENTS D ON E.MANAGER_ID = D.MANAGER_ID
WHERE E.EMPLOYEE_ID = ?
Or are there better solution with less side effects, e.g. order of updates of tables, loading, etc.?
This may be a simple question, but I'm trying to find out if there is a way that I can create a JPQL update query that would allow me to update a single Persisted Entity using a unique column identifier that is not the primary key.
Say I have and entity like the following:
#Entity
public class Customer {
#ID
private Long id;
#Column
private String uniqueExternalID;
#Column
private String firstname;
....
}
Updating this entity with a Customer that has the id value set is easy, however, id like to update this customer entity using the uniqueExternalId without having to pre-query for the local entity and merge the changes in or manually construct a jpql query with all the fields in it manually.
Something like
UPDATE Customer c SET c = :customer WHERE c.uniqueExternalId = :externalId
Is something like this possible in JQPL?
You cannot do it in the exact way you describe - by passing an entity reference, but you can use bulk queries to achieve the same effect.
UPDATE Customer c SET c.name = :name WHERE c.uniqueExternalId = :externalId
Please note that you will have to explicitly define each updated attribute.
It is important to note that bulk queries bypass the persistence context. Entity instances that are managed within the persistence context will not reflect the changes to the records that are changed by the bulk update. Further, if you use optimistic locking, consider incrementing the #Version field of your entities with the bulk update:
UPDATE Customer c SET c.name = :name, c.version = c.version + 1 WHERE c.uniqueExternalId = :externalId
EDIT: The JPA 2.0 spec advises in ยง 4.10:
In general, bulk update and delete operations should only be performed
within a transaction in a new persistence context or before fetching
or accessing entities whose state might be affected by such
operations.
I have a table T with columns defined as usual.
#Entity
#Table(name="T")
public class T {
#Column(name="test_id")
private Long testId;
}
Given entity property "testId", I want to get corresponding DB column name (i.e. "test_id"). How could it be achieved?
Edit 1:
I want to keep this column at separate location with actual DB column name (test_id) than testId. I fetched these values from DB using HQL which have key as entity name (i.e. testId) and I want actual column name in DB.
If I understood your requirement correctly, you want to use HQL while having a consistent name for both DB column and the entity field, like this:
SELECT t.test_id FROM Test t
instead of
SELECT t.testId FROM Test t
There is only one way to do that - renaming the field to test_id. HQL works on entities, not on DB tables, so you must use proper field names in the query.
Since test_id contradicts the usual Java coding conventions, I would advise against it.
EDIT: Getting the annotation attribute value with reflection would work along this outline:
Field field = MyEntity.class.getDeclaredField("testId");
Column a = field.getAnnotation(Column.class);
String columnName = a.name();
I would try to avoid this by any means, but if you're really sure you'll need it, use:
Configuration configuration = sessionFactory.getConfiguration();
PersistentClass persistentClass = configuration
.getClassMapping(T.class.getName());
String columnName = ((Column) persistentClass.getProperty("testId")
.getColumnIterator().next()).getName();
See also Get table column names in Hibernate
Is there a way I can map a field in an hibernate object to be loaded with a table query?
As an example lets say Table_Message has fields id(int),message_key(varchar),message_content(Clob),language(varchar). This table will hold messages in different languages(locale).
And another table thats mapped to an entity using hibernate. Comments with fields id(int),comment_message_id(varchar),created_date(datetime). comment_message_id refers to Table_Message's message_key column.
EDIT: Table_Message is NOT a mapped Entity in hibernate
Assuming my comment class is
public class Comment
{
int id;
String message;
Date createdDate;
}
Is there a way to tell hibernate to load message by joining Comment table and Table_Message table by message_key with a default locale (for example 'en').
Basically is there a way to tell hibernate to load a field by running a specific query? And if so what is that way?
I know about writing a Custom SQL query for loading the entity. But since I'm using XDoclet there doesn't seem to be a way to do that. Also it will be very convenient if there's a way to do that for a single field.
I guess ResultTransformer may help you in this. Please check
http://docs.jboss.org/hibernate/orm/3.3/api/org/hibernate/transform/ResultTransformer.html
http://stackoverflow.com/questions/6423948/resulttransformer-in-hibernate-return-null
You must join the tables by comment_message_id with message_key and further filter the result by language. I assume the message_key is unique.
As a side notice: you should use integer keys to have better performance.
You can try to write a database view in SQL and create an entity to opaque the view:
CREATE VIEW Comment_Table_Message AS
SELECT c.id, c.comment_message_id, c.created_date, m.id AS mid,
m.message_content, m.language
FROM Comment c, Table_Message m
WHERE c.comment_message_id = t.message_key;
Now you can create an entity CommentTableMessage and use JPQL to filter results by language:
SELECT x FROM CommentTableMessage x WHERE x.language=?1
If Table_Message was a Hibernate entity you would write (in JPA terms):
#Entity
public class Comment
{
int id;
#ManyToOne()
#JoinColumn(name="comment_message_id")
TableMessage tableMessage;
String message;
Date createdDate;
}
#Entity
public class TableMessage {
int id;
#Id
String messageKey;
bytes[] messageContent; //I don't know how you want to deal with Blobs?
String language;
}
Having that you can write a simple JPA Query: (Can you use JPA ? - next assumption)
SELECT c FROM Comment c WHERE c.tableMessage.language=?1
Following is a lot of writing for what I feel is a pretty simple issue. Root of issue is my ignorance, not looking so much for code but advice.
Table: Ininvhst (Inventory-schema inventory history) column ihtran (inventory history transfer code) using an old entity mapping I have:
#Basic(optional = false)
#Column(name = "IHTRAN")
private String ihtran;
ihtran is really a foreign key to table Intrnmst ("Inventory Transfer Master" which contains a list of "transfer codes"). This was not expressed in the database so placed a referential constraint on Ininvhst re-generating JPA2 entity classes produced:
#JoinColumn(name = "IHTRAN", referencedColumnName = "TMCODE", nullable = false)
#ManyToOne(optional = false)
private Intrnmst intrnmst;
Now previously I was using JPA2 to select the records/(Ininvhst entities) from the Ininvhst table where "ihtran" was one of a set of values. I used in.value() to do this... here is a snippet:
cq = cb.createQuery(Ininvhst.class);
...
In<String> in = cb.in(transactionType); //Get in expression for transacton types
for (String s : transactionTypes) { //has a value
in = in.value(s);//check if the strings we are looking for exist in the transfer master
}
predicateList.add(in);
My issue is that the Ininvhst used to contain a string called ihtran but now it contains Ininvhst... So I now need a path expression:
this.predicateList = new ArrayList<Predicate>();
if (transactionTypes != null && transactionTypes.size() > 0) { //list of strings has some values
Path<Intrnmst> intrnmst = root.get(Ininvhst_.intrnmst); //get transfermaster from Ininvhst
Path<String> transactionType = intrnmst.get(Intrnmst_.tmcode); //get transaction types from transfer master
In<String> in = cb.in(transactionType); //Get in expression for transacton types
for (String s : transactionTypes) { //has a value
in = in.value(s);//check if the strings we are looking for exist in the transfer master
}
predicateList.add(in);
}
Can I add ihtran back into the entity along with a join column that is both references "IHTRAN"? Or should I use a projection to somehow return Ininvhst along with the ihtran string which is now part of the Intrnmst entity. Or should I use a projection to return Ininvhst and somehow limit Intrnmst just just the ihtran string.
Further information: I am using the resulting list of selected Ininvhst objects in a web application, the class which contains the list of Ininvhst objects is transformed into a json object. There are probably quite a few serialization methods that would navigate the object graph the problem is that my current fetch strategy is lazy so it hits the join entity (Intrnmst intrnmst) and there is no Entity Manager available at that point. At this point I have prevented the object from serializing the join column but now I am missing a critical piece of data.
I think I've said too much but not knowing enough I don't know what you JPA experts need. What I would like is my original object to have both a string object and be able to join on the same column (ihtran) but if this isn't possible or advisable I want to hear what I should do and why.
Pseudo code/English is more than fine.
Can I add ihtran back into the entity
along with a join column that is both
references "IHTRAN"?
Yes. Just make one of them read-only (insertable/updateable=false)
If you are using EclipseLink you could also add a QueryKey for the foreign key.
If you access the relationship before you serialize it then it will be available. Otherwise make it EAGER, or join fetch it in your query.