Filter GAE Key Field with Substring - java

I have a kind named Posts and the key is postId.
The postId format is : YYMMDDXXX. Where XXX is 3 digits sequence number.
For example : 150703001, 150704001, 150704002
How do I get the sequence number from my entities in datastore? I want to convert this SQL Select nvl(max(substring(postId, 7, 3)), 0) from posts where substring(postId, 1, 6) = '150704' to Objectivy filter.
Please help, thanks a lot!

You will have to re-design your Kinds/Entities into a different structure to accomplish this. The datastore can not search by substring.
A possible approach could be this layout :
#Entity
class PostGroup {
#Id
String id; // this is will hold the formatted date YYMMDD
}
#Entity
class Post {
#Id
Long id; // auto generated ID
#Index
Long sequence; // the sequence number
#Parent
Key<PostGroup> group;
}
Now you can set the PostGroup has the ancestor for your Objectify query, sort by Post.sequence desc limit 1 to find the latest post.
String yymmdd = "150704";
Key<PostGroup> postGroupKey = Key.create(PostGroup.class, yymmdd);
Query<Post> query = ofy().type(Post.class).ancestor(postGroupKey).order("-sequence");
Post latestPost = query.first().now();
Note: you don't have to actually persist the PostGroups to use them as ancestors.

Related

Map latest record to an object class by hibernate annotation using condition

I am trying to get only one object mapped by multiple columns.
Simplifying - I have 2 tables:
1) dict_warehouse_item with columns: item_id, date, sequence_prefix and sequence_nb ...
2) warehouse_document_item with columns: ... document_id, item_prefix and item_nb ...
In warehouse_document_item table I have no item_id, but I have item_prefix and item_nb. Unfortunately it can point to many version of the item. It doesn't really matter which one I will choose, but I need it to be mapped to only one. Let's say I want it to be the newest (by date).
Fallowing code gives out an error:
"org.hibernate.mapping.Formula cannot be cast to
org.hibernate.mapping.Column"
#ManyToOne(fetch=FetchType.LAZY)
#JoinFormula(value = "SELECT wi.item_id FROM dict_warehouse_item wi
WHERE (wi.sequence_prefix = item_prefix AND wi.sequence_nb = item_nb)
ORDER BY wi.date DESC LIMIT 1", referencedColumnName = "item_id")
public DictWarehouseItem getDictWarehouseItem() {
return this.dictWarehouseItem;
}
Can someone help me fix this please.

hibernate h2 embeddable list expected "identifier"

I'm trying to associate a list of function (whom Embeddable) within my Employee Entity and H2 seems unhappy with this saying that it expected an "identifier"
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "
CREATE TABLE EMPLOYEE_FUNCTIONS (
EMPLOYEE_EMPLOYEEID VARCHAR(255) NOT NULL,
ACTIVE BOOLEAN NOT NULL,
DEPARTMENTNUMBER INTEGER NOT NULL,
DESCRIPTION VARCHAR(255),
ORDER[*] INTEGER NOT NULL
) "; expected "identifier";
The thing is I already done that with an other project and I don't see why it doesn't work.
Employee.java
#Entity
public class Employee extends AbstractScheduleEntity<EmployeeSchedule> {
public static final String ACOMBA_UNIQUE_FIELD = "acombaUnique";
#Id
#GenericGenerator(name = "sequence_id", strategy =
"ca.tecsar.core.sql.ServerSequenceGenerator")
#GeneratedValue(generator = "sequence_id")
#Column(name = "EmployeeID", unique = true, nullable = false)
private String employeeID;
#ElementCollection
private List<Function> functions;
//getter and setter
}
Function.java
#Embeddable
public class Function implements Serializable {
private int order;
private boolean active;
private String description;
private int departmentNumber;
//getter and setter
}
I removed a few properties in Employee that wasn't necessary.
What may cause this error? Is it because I have a String as identifier in my Employee? If so how can I tell to Hibernate to add Employee_EmployeeID as identifier?
Thanks
Turns out I was being dumb and named a column "Order". Wonder why H2 wasn't happy :upside_down:
Changed the variable name to something else and it worked!
I have the same problem while naming the fields: private String to and private String from , changed to ex. dayTo , dayFrom , and it worked.
Got same issue with Order as entity. Changed table name to "orderz" and goes on.
I had the same problem with Spring and H2 database for tests, My entity had the field name "interval", I renamed to "inter" and resolved the problem.
So, these errors happen due to a sql reserved names in entities.
I was facing a similar issue because of a field in my entity called "interval".
The answers to this post help me identify the root cause, however changing the name of the field was not a solution for me because "interval" was perfect for my class.
The solution I used was to rename the table column by using hibernate annotation.
#Column(name = "FREQUENCY_INTERVAL")
private int interval;
This helped me keep the variable name as 'interval' while mapping to a column name that is acceptable by the database.
I also had an issue with an entity field called row as it is also a keyword
I specified a Column name ("SEAT_ROW") to get around it.
#Entity
data class Seat (
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
val id : Long,
#Column(name="SEAT_ROW")
val row : Char,
val num : Int,
val price : BigDecimal,
val description : String
) {
override fun toString(): String = "Seat $row-$num $$price ($description)"
}
H2 Compatibility and Keywords Table
I was using order as table name in h2. Changed to something like _order and I get it!
As you can see here, order is a reserved word by h2.
try to put the ; before the " and test ?
in my case problem cause was incorrect syntax in insert statement
problem :
insert into 'table name missing' (column names...) values(values...);
after adding table name
fix:
insert into 'table name specified' (column names...) values(values...);
some times trivial mistakes are hard to spot :)
I had the somewhat same problem but instead mine was missing a semi-colon.

Hibernate and JPA annotations - persist a list of phrases

I'm having trouble using hibernate to persist a simple java object containing just a list of phrases in the form of strings.
To store this in a MySql database I have two tables:
phrase_list - columns:
group_id, phrase_id, list_position (which together make up the primary key; also there is a foreign key constraint on phrase_id from the phrase table)
phrase - columns: phrase_id, phrase (phrase is a varchar with a unique index)
I would like to simply be able to annotate the object containing the list of phrases in order to persist it, but nothing I've tried has worked, I've tried examples and variations of using #ElementCollection and #OneToMany with another Entity representing the phrase, but no matter what I try I can't seem to get this to work.
For example a phrase list: {"a","b","b"} would be stored as:
**(phrase table)** **(phrase_list table)**
phrase_id phrase group_id phrase_id list_position
1 'a' 1 1 0
2 'b' 1 2 1
1 2 2
Here is the attempt to what I thought would work; I added an extra id field because I could see no way to use the foreign key as part of the id, and annotating the list with #Id didn't work.
#Entity #Table(name = "phrase_list")
public class PhraseList {
#ElementCollection
#CollectionTable(
name="phrase",
joinColumns=#JoinColumn(name="phrase_id")
)
#OrderColumn(name="list_position")
#Column(name="phrase")
private List<String> phrases;
#Id #GeneratedValue
#Column(name = "list_id")
private Long id;
#Column(name = "goup_id")
private Long groupId;
public void setResults(List<String> results){
this.results = results;
}
public void setGroupId(Integer groupId) {
this.groupId = groupId;
}
}
I get this exception:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Cannot add or update a child row: a foreign key constraint fails (test_db.phrase_list, CONSTRAINTfk_phrase_list_phrase_idFOREIGN KEY (phrase_id) REFERENCESphrase(phrase_id`) ON DELETE NO ACTION ON UPDATE )
Is there any way to get this to work simply by annotating the plain Java object? If not what is the best way to achieve this?
If I can't get it to work with annotation I would probably write custom queries and/or specialized methods for persisting the object. I.e., a method that is coupled to that particular class in knowing how to persist its objects, which I hoped to avoid.

JPA Mapping Multi-Rows with ElementCollection

I'm trying to follow the JPA tutorial and using ElementCollection to record employee phone numbers:
PHONE (table)
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
Short version
What I need is a class like this:
#Entity
#Table(name="Phones")
public class PhoneId {
#Id
#Column(name="owner_id")
long owner_id;
#Embedded
List<Phone> phones;
}
that stores each person's phone numbers in a collection.
Long version
I follow the tutorial code:
#Entity
#Table(name="Phones")
public class PhoneId {
#Id
#Column(name="owner_id")
long owner_id;
#ElementCollection
#CollectionTable(
name="Phones",
joinColumns=#JoinColumn(name="owner_id")
)
List<Phone> phones = new ArrayList<Phone>();
}
#Embeddable
class Phone {
#Column(name="type")
String type = "";
#Column(name="number")
String number = "";
public Phone () {}
public Phone (String type, String number)
{ this.type = type; this.number = number; }
}
with a slight difference that I only keep one table. I tried to use the following code to add records to this table:
public static void main (String[] args) {
EntityManagerFactory entityFactory =
Persistence.createEntityManagerFactory("Tutorial");
EntityManager entityManager = entityFactory.createEntityManager();
// Create new entity
entityManager.getTransaction().begin();
Phone ph = new Phone("home", "001-010-0100");
PhoneId phid = new PhoneId();
phid.phones.add(ph);
entityManager.persist(phid);
entityManager.getTransaction().commit();
entityManager.close();
}
but it keeps throwing exceptions
Internal Exception: org.postgresql.util.PSQLException: ERROR: null
value in column "type" violates not-null constraint Detail: Failing
row contains (0, null, null). Error Code: 0 Call: INSERT INTO Phones
(owner_id) VALUES (?) bind => [1 parameter bound] Query:
InsertObjectQuery(tutorial.Phone1#162e295)
What did I do wrong?
Sadly, i think the slight difference that you only keep one table is the problem here.
Look at the declaration of the PhoneId class (which i would suggest is better called PhoneOwner or something like that):
#Entity
#Table(name="Phones")
public class PhoneId {
When you declare that a class is an entity mapped to a certain table, you are making a set of assertions, of which two are particularly important here. Firstly, that there is one row in the table for each instance of the entity, and vice versa. Secondly, that there is one column in the table for each scalar field of the entity, and vice versa. Both of these are at the heart of the idea of object-relational mapping.
However, in your schema, neither of these assertions hold. In the data you gave:
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
There are two rows corresponding to the entity with owner_id 1, violating the first assertion. There are columns TYPE and NUMBER which are not mapped to fields in the entity, violating the second assertion.
(To be clear, there is nothing wrong with your declaration of the Phone class or the phones field - just the PhoneId entity)
As a result, when your JPA provider tries to insert an instance of PhoneId into the database, it runs into trouble. Because there are no mappings for the TYPE and NUMBER columns in PhoneId, when it generates the SQL for the insert, it does not include values for them. This is why you get the error you see - the provider writes INSERT INTO Phones (owner_id) VALUES (?), which PostgreSQL treats as INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null), which is rejected.
Even if you did manage to insert a row into this table, you would then run into trouble on retrieving an object from it. Say you asked for the instance of PhoneId with owner_id 1. The provider would write SQL amounting to select * from Phones where owner_id = 1, and it would expect that to find exactly one row, which it can map to an object. But it will find two rows!
The solution, i'm afraid, is to use two tables, one for PhoneId, and one for Phone. The table for PhoneId will be trivially simple, but it is necessary for the correct operation of the JPA machinery.
Assuming you rename PhoneId to PhoneOwner, the tables need to look like:
create table PhoneOwner (
owner_id integer primary key
)
create table Phone (
owner_id integer not null references PhoneOwner,
type varchar(255) not null,
number varchar(255) not null,
primary key (owner_id, number)
)
(I've made (owner_id, number) the primary key for Phone, on the assumption that one owner might have more than one number of a given type, but will never have one number recorded under two types. You might prefer (owner_id, type) if that better reflects your domain.)
The entities are then:
#Entity
#Table(name="PhoneOwner")
public class PhoneOwner {
#Id
#Column(name="owner_id")
long id;
#ElementCollection
#CollectionTable(name = "Phone", joinColumns = #JoinColumn(name = "owner_id"))
List<Phone> phones = new ArrayList<Phone>();
}
#Embeddable
class Phone {
#Column(name="type", nullable = false)
String type;
#Column(name="number", nullable = false)
String number;
}
Now, if you really don't want to introduce a table for the PhoneOwner, then you might be able to get out of it using a view. Like this:
create view PhoneOwner as select distinct owner_id from Phone;
As far as the JPA provider can tell, this is a table, and it will support the queries it needs to do to read data.
However, it won't support inserts. If you ever needed to add a phone for an owner who is not currently in the database, you would need to go round the back and insert a row directly into Phone. Not very nice.

Hibernate: Criteria API: Query entities which do not contain a specified element in a CollectionOfElements?

Let's say I have the following two classes; User and Location. I want to create a DetachedCriteria to query the user table, and return all users who do not have a location with the name "xyz".
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#CollectionOfElements
Set<Location> locations;
}
#Entity
public class Location{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#Column
String name;
}
The following code will return all users who DO have a location with name "xyz" set:
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
dc.createCriteria("locations")
dc.add(Restrictions.eq("name", "xyz"));
If I change to Restrictions.ne(), that doesn't work, because it will only return users who actually have locations set. Also, if there are a bunch of locations set for a user, it will duplicate that user over and over.
Any ideas?
Using the entities User and Location as described in your original post:
1) Check if the associated locations is empty.
Junction or = Restrictions.disjunction();
or.add(Restrictions.isEmpty("locations"));
2) Create an associated criteria for locations using a LEFT_JOIN and an alias to be used in the "ne" restriction. The LEFT_JOIN is required so we still get User records back even if the locations relationship is empty.
userCriteria.createCriteria("locations", "loc", Criteria.LEFT_JOIN);
or.add(Restrictions.ne("loc.name", "xyz"));
3) Add the disjunction to the the original User criteria.
userCriteria.add(or);
You'll probably need to use some combination of Restrictions.and(), Restrictions.not(), Restrictions.or() and Restrictions.in() to get your inverse-logic to work right. Check http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Restrictions.html - it can definitely be done!
To ensure you only get at-most-one User, use a Distinct projection (http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Distinct.html) via the Projections.distinct() factory method (http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Projections.html)- i.e.:
dc.setProjection(Projections.distinct(Projections.property("id")));
Something like that should do what you need.

Categories