We use Oracle as our database. It has a limit of 4000 characters for its VARCHAR2 datatype. So, when I wanted to persist some *long* String data, I had to come up with something more than just one VARCHAR2 column.
I originally looked at using a CLOB, but after investigating the effort required to deal with Oracle CLOBs, I decided to pass.
The solution I came up with was to break the String into 4000-character Strings and persist them as a 1-N. Basically the table looks like this:
Code:
PARENT_ID
SEQ
TEXT
Piece of cake. Next I wanted a component that encapsulated this structure, so I came up with LongString:
Code:
public class LongString {
private List stringList = Collections.EMPTY_LIST;
public List getStringList() {
return stringList;
}
public void setStringList(List list) {
stringList = list;
}
public String getText() {
if (stringList.size() == 0) {
return null;
}
StringBuffer text = new StringBuffer(4000 * stringList.size());
for (int i = 0; i < stringList.size(); i++) {
text.append(stringList.get(i));
}
return text.toString();
}
public void setText(String text) {
if (text == null) {
stringList = Collections.EMPTY_LIST;
}
stringList = new ArrayList();
for (int i = 0; i < ((text.length() - 1) / 4000) + 1; i++) {
int start = i * 4000;
int end = Math.min(start + 4000, text.length());
stringList.add(text.substring(start, end));
}
}
}
Now any class that wants to have some long text, it uses that LongString as so:
Code:
public class Contest {
private LongString html = new LongString();
/**
* @hibernate.list
* table="text"
* lazy="true"
* cascade="all"
*
* @hibernate.collection-key
* column="parent_id"
*
* @hibernate.collection-index
* column="sequence"
*
* @hibernate.collection-element
* column="text"
* type="string"
*/
private List getHtmlList() {
return html.getStringList();
}
private void setHtmlList(List htmlList) {
html.setStringList(htmlList);
}
public String getHtml() {
return html.getText();
}
public void setHtml(String html) {
this.html.setText(html);
}
}
The html get/set pair is exposed to the application so the persistance implementation is hidden. The htmlList get/set pair is private and for Hiberante's eyes only.
This leads me to my questions:
Althought the scruture of the LongString is captured in one class, having to expose the List in enclosing classes via private methods is still yucky. To me, it still let's some of the Hibernate-related stuff leak out into my other classes.
I don't like the fact the LongString can't make defensive copies of its data. Maybe it can, but when I tried it, Bad Stuff happened.
Without the defensive copying, you can do stuff like:
Code:
LongString longString = new LongString();
List stringList = new ArrayList();
stringList.add("Some String");
longString.setStringList(stringList);
stringList.clear(); // oh no - we just blew away our LongString!
What are some other solutions to persisting long Strings in Oracle without resorting to CLOBs?
Thanks.
Ryan