I've implemented store_mapping extension but it currently uses ObjectAsStringMapping. As a result I can read array values from database but any insert or update causes underlying postgresql driver error "INTEGER[]" is not "VARCHAR".
Is there any way to implement PGSQL arrays in JDO? It looks quite flexible with all that extension points. Any hints on extension points I have to implement are appreciated, thanks in advance!
Edit:
I'm using postgres int8 as a bit field as a "replacement" for arrays after I figured out that I'll be okay with 63 possible values.
Sample class would be:
#PersistenceCapable(detachable="true", table="campaigns")
public class Campaign implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
public Long id;
public List<Integer> regions;
}
And I think I have to implement some mapping from List to java.sql.Array but still didn't figure out how to do that. I could write extension and override default behavior but what extension-point should it be?
Looks like you need to build a custom field strategy to handle the mapping.
The key then is to transform the representation in this case to PostgreSQL array representation, namely a comma separated value (with " escaping text with any special characters but can be used on all values, double quotes are escaped by doubling them). The string is then bracketed betweed { and }. So ARRAY[1,2,3]::int[] becomes '{1,2,3}' or '{"1","2","3"}'
Related
I have recently started to use Spring Data MongoDB and I wonder if there is any way to avoid writing entities' attributes explicitly as they are stored in the database. For example, given the following class representing a MongoDB collection:
public class Employee {
#Id
public String id;
private double salary;
...
}
If I want to make a query using MongoTemplate like:
public List findEmployeeBySalaryRange(double salary) {
Query query = new Query();
query.addCriteria(Criteria.where("salary").lt(salary));
...
}
I would like to avoid writing "salary", since that will make the code harder to maintain in the future in case the field name changes. I am thinking of something like getting the field name from the class attribute, but I am not quite sure how. Is there a way to do it? I have looked into the documentation but did not find anything related unless I missed it.
Thanks in advance.
You may create a Utility Class to store all database field names, use #Field annotation on field with constant from that class and use that constant in query to avoid error prone hardcoded Strings.
In Employee Model
#Field(DbFields.SALARY)
private double salary;
In Query,
query.addCriteria(Criteria.where(DbFields.SALARY).lt(salary));
In DbFields Utility class
public static final String SALARY = "salary";
I'm coding an app/game where user inputs his own rules on textfields stored in a SQFLite database.
Rules are related to a friend, so it's in a class Friend, with an id, name, rule0, rule1, rule2...rule9. Which is REALLY annoying for a lot of reasons, but I think I need it to be in Friend class so it get stored with the right friend.id.
I got the obvious error 'only static members can be accessed on initializers' when i try
List<Strings> rules = [rule0, rule1];
or
List<dynamic> rules = [...];
Does anyone knows how I could fix this ?
Create a new class Rules and each rule has ID related to the right friend ?
Or if I can just create a dynamic list whithin Friend ?
Really lost on this. Any help is welcome.
class Friend {
int id;
String name;
String pic;
bool play;
String rule0;
String rule1;
String rule2;
String rule3;
String rule4;
String rule5;
String rule6;
String rule7;
String rule8;
String rule9;
Friend();
// i have then a fromMap() and a toMap() for the database
}
I'm not completely sure, but it seems like you're having trouble with both the SQL aspect as well as the class representation of your data.
If you know for sure there will only be a set number of rules, you could approach it in the way you currently have. The addition I'd do is to make a 'getter' function for the list of rules i.e.
List<String> get rules => [rule1, rule2, rule2, ...].where((item) => item != null).toList()
Note that if you were using a constructor, you could instead build the list in the constructor as follows:
class Friend {
int id;
String name;
String pic;
bool play;
String rule0;
String rule1;
String rule2;
String rule3;
String rule4;
String rule5;
String rule6;
String rule7;
String rule8;
String rule9;
List<String> rules;
Friend(
{this.id,
this.name,
this.pic,
this.play,
this.rule0,
this.rule1,
this.rule2,
this.rule3,
this.rule4,
this.rule5,
this.rule6,
this.rule7,
this.rule8,
this.rule9})
: rules = [
rule0,
rule1,
rule2,
rule3,
rule4,
rule5,
rule6,
rule7,
rule8,
rule9,
].where((item) => item != null).toList(growable: false);
}
I wouldn't recommend that though (or if you do, you should probably be making either rule* or rules private or maintaining state somehow). The list of strings doesn't store references to the rule0, rule1, ... strings but rather stores the strings themselves. You could get around this by making a Rule class and making rule0-9 final, but that's getting a bit complicated.
It most likely makes more sense for this to be a dynamic list of items. SQL doesn't handle that, so you're going to have to make a separate table for rules.
You'll have two tables something like this, where id are both PRIMARY KEYs and friendId is a FOREIGN KEY:
Friend(id, name, pic, play) and Rule(id, friendId, text)
Saving and updating will become more complicated now. You'll have to be more careful about maintaining the list of rules in the database, but it isn't all that difficult. If you know that you'll only be writing to the list from one location (i.e. one class), you could keep the difference between what the class's current state and the initial state were, but realistically unless you're dealing with 10's of thousands of rules, it probably won't matter appreciably.
I'm not sure if this is possible at all, but is there a way to override the Comparable used by a Google App Engine property when used in a query? For example, there is a property type PhoneNumber (basically a String) that in the docs has a method:
public int compareTo(PhoneNumber o)
Specified by:
compareTo in interface java.lang.Comparable<PhoneNumber>
The exact workings of how it compares I haven't been able to find. Is there a way to override that Comparable so that it compares it in a way I choose?
Thanks
No. But you can sort any collection any way you want. Since you tagged this with objectify:
#Entity
public class Thing {
private static final Comparator<PhoneNumber> SPECIAL_COMPARATOR = // make one
// ... id, etc
SortedSet<PhoneNumber> phoneNumbers = new TreeSet<>(SPECIAL_COMPARATOR);
}
This won't help you if you need the phone numbers indexed in a particular way (although collection property index sorting would be very strange anyways). If you have a single indexed phone number property and you want to control index ordering, you need to create your own PhoneNumber that translates to a correctly-sorted String representation. You'll need to register your own PhoneNumberTranslatorFactory with Objectify. This is not hard; look at the source code for examples.
I'm new to Solr, and I'm trying to use Solrj pojo's to create my documents.
Is there a mapping of Solr types to Java I should adhere to in my pojo's? is everything in the pojo a String? is there a magical mapping from Java basic types to Solr and it's transparent?
This seems like a basic question but I can't find an answer.
TIA.
You can map pojo with solr types using #Field annotation of solrj
below is the example code
import org.apache.solr.client.solrj.beans.Field;
public class Person {
#Field
private int id;
#Field("first_name")
private String firstName;
#Field("last_name")
private String lastName;
#Field
private String age;
// Getters & setters
}
your schema.xml should contain the fields id, first_name, last_name, age.
The answer to this question appears to be that for Solrj beans (using #Field) the Java type of the field is a Java OBJECT that corresponds to the solr.*Field type.
For instance solr.BoolField maps to java.lang.Boolean.
Same follows for Long, Integer, Float, ...
I hope this helps the next poor soul :-)
Solrj can stream the document as XML or Binary using the RequestWriter. The document.addField method does take an object, so it is ok to pass Java datatypes, but I have not seen a mapping. If there is one it probably assumes the basic data types. If you look at the example code it is so.
If I remember correctly (this was from a while back), we just had an issue with dates, and wrote our own formatter for it. This was from the Solr 1.2 days and that code worked fine and is still in production
http://lucene.apache.org/solr/api-4_0_0-BETA/org/apache/solr/common/SolrInputDocument.html
Here is the JavaDoc for the InputType. http://lucene.apache.org/solr/api-4_0_0-BETA/org/apache/solr/common/SolrInputField.html
Some Background
I have a game database with a table called Games that has multiple attributes and one called Genres. The Genres attribute is defined as an integer[] in PostgreSQL. For the sake of simplicity, I'm not using any foreign key constraints, but essentially each integer in this array is a foreign key constraint on the id attribute in the Genres table. First time working with the NetBeans Master/Detail Sample Form and Java persistence and it's been working great so far except for 1 thing. I get this error when the program tries to display a column that has a 1-dimensional integer array. In this example, the value is {1, 11}.
Exception Description: The object [{1,11}], of class [class org.postgresql.jdbc3.Jdbc3Array], from mapping [oracle.toplink.essentials.mappings.DirectToFieldMapping[genres-->final.public.games.genres]] with descriptor [RelationalDescriptor(finalproject.Games --> [DatabaseTable(final.public.games)])], could not be converted to [class [B].
Exception [TOPLINK-3002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ConversionException
My Research
From what I've been able to read, it looks like PostgreSQL arrays need something special done to them before you can display and edit them in this template. By default, the sample form uses TopLink Essentials (JPA 1.0) as its persistence library, but I can also use Hibernate (JPA 1.0).
Here is the code that needs to be changed in some way. From the Games.java file:
#Entity
#Table(name = "games", catalog = "final", schema = "public")
#NamedQueries({
// omitting named queries
#NamedQuery(name = "Games.findByGenres", query = "SELECT g FROM Games g WHERE g.genres = :genres")
})
public class Games implements Serializable {
#Transient
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private static final long serialVersionUID = 1L;
// omitting other attributes
#Column(name = "genres")
private Serializable genres;
// omitting constructors and other getters/setters
public Serializable getGenres() {
return genres;
}
public void setGenres(Serializable genres) {
Serializable oldGenres = this.genres;
this.genres = genres;
changeSupport.firePropertyChange("genres", oldGenres, genres);
}
} // end class Games
Here are also some of the sites that might have the solution that I'm just not understanding:
https://forum.hibernate.org/viewtopic.php?t=946973
http://blog.xebia.com/2009/11/09/understanding-and-writing-hibernate-user-types/
// omitted hyperlink due to user restriction
Attempted Solutions
I'm able to get the data to display if I change the type of genres to String, but it is immutable and I cannot edit it. This is what I changed to do this:
#Column(name = "genres")
private String genres;
public String getGenres() {
return genres;
}
public void setGenres(String genres) {
String oldGenres = this.genres;
this.genres = genres;
changeSupport.firePropertyChange("genres", oldGenres, genres);
}
I also attempted to create a UserType file for use with Hibernate (JPA 1.0), but had no idea what was going wrong there.
I also attempted to use the #OneToMany and other tags, but these aren't working probably because I'm not using them properly.
What I'm Looking For
There has to be a simple way to get this data to display and make it editable, but since I'm completely new to persistence, I have no idea what to do.
The effort put into your question shows. Unfortunately JPA does not currently support PostgreSQL arrays. The fundamental problem is that arrays are not frequently used in many other databases frequently and so heavy reliance on them is somewhat PostgreSQL specific. Thus you can expect that general cross-db persistence API's are not generally going to support them well if at all. JPA is no exception, having currently no support for PostgreSQL arrays.
I have been looking at writing my own persistence API in Java that would support arrays, but it hasn't happened yet, would be PostgreSQL-only when written, and would be based on a very different principle than JPA and friends.