Vaadin SQLContainer

Also I should say:

ComparisonTypes
STARTS_WITH, ENDS_WITH, CONTAINS
look like leaky abstraction - pain without gain ;-(

(ENDS_WITH, CONTAINS are also DBA hell)

I think one single “LIKE” instead of them will be better.
With LIKE user can supply standard more powerful
like-expression
e.g. “som_ lett%” (where _ and % are special).
Some SQL servers have much more powerful like syntax (with ranges, etc). You needn’t rewrite SQL server in plugin.

Then getPreparedStatementValue method can be removed.

In “passes” method you can use simple hand-made like analog (easy to write yourself, also can be found in string manipulation libraries)

Sorry for so many posts, but You see: I love SQLContainer :wink:

It will be good to have bundled in Vaadin core PropertyConverter (from org.vaadin.customfield.PropertyConverter)
and ItemConverter (simple Item wrapper, delegates all calls to other item, but You can “wrap” some properties in PropertyConverter).

Then SQLContainer can introduce RowIdPropertyConverter:

in your Form’s setItemDataSource you wrap newDataSource in ItemConverter and wrap it’s foreign key properties in RowIdPropertyConverter. Then all conversion between refId:int <->RowId will be made automaticly.

See “cities” ComboBox and PersonForm in tutorial for problem understanding.

PS: Vote for ItemConverter
here

RowIdPropertyConverter is a very interesting concept. I’m facing the exact same issue with my pet project container. There is a similar concept in BeanContainer.

I believe that the concept should be looked at for all database containers with foreign keys !

Can anyone explain when one would use SQLContainer.addReference() and its correct usage? I am was hoping that I could use this method to relate two SQLContainer objects together using a foreign key and that it would generate SQL performing a join. For example:

TableQuery q1 = new TableQuery("ui_group", connectionPool, new OracleGenerator());
q1.setVersionColumn("VERSION");
SQLContainer uiRuleGroupContainer = new SQLContainer(q1);   	

TableQuery q3 = new TableQuery("ui_rule", connectionPool, new OracleGenerator());
q3.setVersionColumn("VERSION");
SQLContainer uiRuleContainer = new SQLContainer(q3);
	        
uiRuleContainer.addReference(uiRuleGroupContainer, "GROUP_ID", "GROUP_ID");

In my schema, the UI_RULE table has a foreign key column called GROUP_ID that references the UI_GROUP table (whose primary key is GROUP_ID). I know that I can use FreeformQuery and implement a FreeformStatementDelegate and write my own raw SQL to join these tables together but it would be cool if I could simply use the above approach.

Ultimately, I want to display the joined database tables in one Vaadin Table.

Thanks for the help.

Hi.
I would like to populate tree component from Database please tell me in which way is better to do. Do I have to create several tables for that or It’s possible to do using one table. Which way is more comfortable to use using SQLContainer. And Is there an example populating tree using SQLContainer.
Please help me with this question.

Best regards,
Manvel Saroyan

Hello Manvel,

It should be fairly easy to implement the Container.Hierarchical interface for the SQLContainer (for your specific case) if you extend SQLContainer. This would be for the case where you have your tree data in a single table. Most of the methods would be pretty straight forward to implement and for the trickier ones, see HierarchicalContainer for an example implementation.

Unfortunately there are no examples of how to implement this specifically with SQLContainer.

HTH,
/Jonatan

Hi Jonatan.

I was wondering if you took at look at my question posted back on 3/5/11 4:33 PM regarding joining to SQLContainers together to perform a table join?

Thanks.

-Jordan

Hi Jordan,

Unfortunately the SQLContainer does not currently support automatic generation of join statements. This feature has been planned to be implemented at some point but I don’t think there is a schedule for when this would be done.

The addReference and related methods are purely on the Java-side, not touching the database as such. They are merely a means for the lazy of us to do certain things a bit easier. This should be quite well explained in the chapter 4.4 of the SQLContainer manual.

In short, the functionality is basically identical to creating two SQLContainers, then manually fetching a foreing key from one container and fetching the correct item based on the foreign key from the other container. Hence, no SQL joins are involved. This merely allows you to skip a few lines of code by calling the getReferencedItem on the first container.

Bottom line: To use SQL joins you currently have to use FreeFormQuery and implement the FreeformStatementDelegate to generate the required statements.

Hi Jonatan,
Thank you for your fast reply

Now I went quite a forward with that coonection. Here is how.

It’s the class that extends SQLContainer and implements Container.Hierarchical Interface :


public class HierarchicalConnection extends SQLContainer implements  Container.Hierarchical  {

	public HierarchicalConnection(QueryDelegate delegate) throws SQLException {
		super(delegate);
	}

	public Collection<?> getChildren(Object itemId) {
		ArrayList<Object> myList = new ArrayList<Object>();
		/// CREATING ITERATOR TO ITERATE TO COMPARE PARENTID WITH ID's /// 
		for (Object id : getItemIds()) {
			if ((Integer) getItem(id).getItemProperty("parentID").getValue() == (Integer) getItem(itemId).getItemProperty("id").getValue()){
				myList.add(id);
			}
		}
		return myList;
	}

	public Object getParent(Object itemId) {
	
		return getContainerProperty(itemId, "parentID");
	}

	public Collection<?> rootItemIds() {
		
		ArrayList<Object> myList = new ArrayList<Object>();
		//// ITERATING TO GET ROOT ITEMS /////
		Object aa= 0;
		for (Object id : getItemIds()) {
			
			if ((Integer) getItem(id).getItemProperty("parentID").getValue()==0){
				System.out.println(getItem(id).getItemProperty("parentID"));
				myList.add(id);
			}
		}
	
		return myList;
	}

	public boolean setParent(Object itemId, Object newParentId)
			throws UnsupportedOperationException {
		return true;
	}

	public boolean areChildrenAllowed(Object itemId) {
	
		if (Integer.parseInt(getItem(itemId).getItemProperty("leaf").toString())==1) {
			return false;
		}
		
		return true;
	}

	public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed)
			throws UnsupportedOperationException {
		return true;
	}

	public boolean isRoot(Object itemId) {
		return true;
	}

	public boolean hasChildren(Object itemId) {
		return true;
	}
}

And here is what I get :

So It works, But it works only for a small database table, but my real table contains 1000 rows. When I Use it with tableQuery and click on nodes. My JVM and MYSQL processes go to near 50% of CPU and operations are done veryslowly (displaying childes).
How can I figure out this situation.

I think If I’ll create 3 tables for each my nodes maybe it’ll be solution ???
What you think ?

Best Ragards,
Manvel Saroyan

I’ve already solved the problem about big database.
I’ve created another container of that table and added filter on that container and got the children nodes :


SQLContainer child = myCont.getChildrenPlan();  /// ANOTHER CONTAINER
Filter aa = new Filter("parentID", ComparisonType.EQUALS,	(Integer) getItem(itemId).getItemProperty("id").getValue());
child.addFilter(aa);
myList.addAll(child.getItemIds());
child.removeAllContainerFilters("parentID");

So it’s begin works very fast. I think the problem was because Iterator. I think it was to hard to iterate over big table for JVM. But for MYSQL it wasn’t a problem.

Thanks to all developers for ideas.

Here is final Code FOR people who will search for sollution:


public class HierarchicalSQLContainer extends SQLContainer implements  Container.Hierarchical  {
	private SQLContainer childrenContainer;
	
	public HierarchicalSQLContainer(QueryDelegate delegate) throws SQLException {
		super(delegate);
		childrenContainer = new SQLContainer(getQueryDelegate());
	}

	public Collection<?> getChildren(Object itemId) {
		Filter myFilter = new Filter("parentID", ComparisonType.EQUALS,
				(Integer) getItem(itemId).getItemProperty("id").getValue());
		childrenContainer.addFilter(myFilter);
		ArrayList<Object> myList = new ArrayList<Object>();
		myList.addAll(childrenContainer.getItemIds());
		childrenContainer.removeContainerFilters("parentID");
		return myList;
	}

	public Object getParent(Object itemId) {
		return getContainerProperty(itemId, "parentID");
	}

	public Collection<?> rootItemIds() {
		Filter myFilter = new Filter("parentID", ComparisonType.EQUALS,0);
		addFilter(myFilter);
		ArrayList<Object> myList = new ArrayList<Object>();
		myList.addAll(getItemIds());
		removeContainerFilters("parentID");
		return myList;
	}

	public boolean setParent(Object itemId, Object newParentId)
			throws UnsupportedOperationException {
		return true;
	}

	public boolean areChildrenAllowed(Object itemId) {
		if ((Integer)getItem(itemId).getItemProperty("leaf").getValue()==1) {
			return false;
		}
		return true;
	}

	public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed)
			throws UnsupportedOperationException {
		return true;
	}

	public boolean isRoot(Object itemId) {
		return true;
	}

	public boolean hasChildren(Object itemId) {
		return true;
	}
}


ticket 6650

Hi DEAR SQLContainer Developers .
I’m having such problem → I’m testing timeLine Addon using SQLContainer as datasource, But I’m having a problem, because timeLine as I explored is using Indexed container. So please give me an Idea how to make SQLContainer works with timeline, I’ve Created my own class-> IndexedSQLContainer that I’ve extended from SQLContainer and implements Container.Indexed. But I’m getting null poin exception.
Here is my IndexedSQLContainer class:


public class IndexedSQLContainer extends SQLContainer implements Container.Indexed {

	public IndexedSQLContainer(QueryDelegate delegate) throws SQLException {
		super(delegate);
		// TODO Auto-generated constructor stub
	}
}

And here is my timeLine declaration code:

public class VichakagrutyunTimeLine extends Timeline {
	
	public VichakagrutyunTimeLine () {
		setSizeFull();
		IndexedConnection indexedConnection = new IndexedConnection();
		indexedConnection.regIndexedContainer();
		IndexedSQLContainer indexedContainer = indexedConnection.getIndexedContainer();
		
		
		System.out.println(indexedContainer.getItem(indexedContainer.firstItemId()).getItemProperty("name").getValue());
		
		addGraphDataSource(indexedContainer);
		setGraphTimestampPropertyId(indexedContainer, "date");
		setGraphValueProperyId(indexedContainer, "name");
	}

Please tell me the way that I can make timeline works with SQLContainer and which method’s of indexed container do I have to declare to make things work.

Best Reagards,
Manvel Saroyan

Hi,

I’ve been having a problem with SQLContainer, and it was suggested that I re-submit my question here. The original discussion is located at: http://vaadin.com/forum/-/message_boards/message/347072

Basically, I have successfully gotten an SQLContainer to read one of my database tables, display it in a UI table, add records to the database, and then fail miserably when I try to delete a record. The error I’m getting looks like this:

Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘AND “startTime” = ‘1/2/3333 1:23’ AND “stopTime” = ‘1/2/3333 1:24’’ at line 1

As you can see from the other discussion thread, a test program was given to me that I implemented and it worked fine - deleted a database record without any problem. Replacing that database table with my own table fails. Also note that in my (failing) program, I have 4 other database tables that add and delete records successfully - so it is something specific to this database table that I’m doing wrong.

I could really use some help in tracking this down - I’m brand new to Vaadin and trying to figure out how it works along the way… I’m willing to assume that I’ve done something stupid (history tells me this is often a
valid assumption :)) but I’d be grateful if someone could show me exactly how I’m being stupid…

A couple of specific questions:

  1. Is there some way of figuring out exactly what the SQL prepared statement looks like? I’m seeing what looks like the end of it here… It would be nice to see if the whole statement executes properly from the command line.

  2. The fields startTime and stopTime are variable length character strings at the end of my database record definition. Since I’m providing the oid of the key field of the record (named ‘id’ in this case), why is it trying to execute a statement including the start and stop times - shouldn’t it be deleting the record where id = ???

The code being executed is simply this:

public boolean delMaintenanceRecord(Object oid){
boolean retval = false;
try{
Logger.info("Delete Maintenance Record - OID = " + oid);
retval = sqc_MaintRec.removeItem(oid);
sqc_MaintRec.commit(); /***** EXCEPTION occurs here…
retval = true;
} catch(Exception e){
Logger.error("Exception: " + e);
e.printStackTrace();
retval = false;
}

	return(retval);
}

I’ll be happy to provide any other information you need - just ask. Feel free to contact me directly if you want to avoid taking up bandwidth on this message board - I can provide a summary once I have a solution…

Thanks in advance,

nbc

I noticed That SQLContainer class already implements Container.Indexed interface. But I still having problem here is what I call :

addGraphDataSource(mySQLContainer, "date", "name");

And I get error that says:
The timestamp must be of type java.util.Date

Maybe it’s because SQLContainer gets java.sql.Date object ???

Please help me to finish with my headache.

Best Regards,
Manvel Saroyan

Hi,

This indeed seems to be a problem with Timeline as it requires the timestamp property to be java.util.Date and does not accept any class that extends java.util.Date. I created
#6699
for this, should be fixed in the next release, which we hope to get out in 1-2 weeks.

I don’t directly see how it could be easily worked around but if you copy/paste the Timeline.class and change the

if (clazz == java.util.Date.class) { in setGraphTimestampPropertyId to if (java.util.Date.class.isAssignableFrom(clazz)) { it should work.

EDIT: Created an example of using SQLContainer and Timeline together. Application at
http://artur.virtuallypreinstalled.com/SQLTimeline
, code at
http://dev.vaadin.com/svn/incubator/SQLTimeline/
. Includes the modified Timeline class that works with SQLContainer

Hi Artur Signell Thank you very much… Finally it’s works…
At first I was having problems but it’s finally works…
Thanks
:grin:

I have a bit more information on my container problem - perhaps someone can point me in the right direction. My mysql database table is defined like this:

mysql> describe maintenance;
±-----------------±--------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±-----------------±--------------±-----±----±--------±---------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| parentId | int(11) | NO | | NULL | |
| uid | int(11) | NO | MUL | NULL | |
| recType | int(11) | NO | | NULL | |
| sgid | int(11) | NO | MUL | NULL | |
| maintName | varchar(64) | NO | | NULL | |
| enteredHostList | varchar(4096) | NO | | NULL | |
| expandedHostList | varchar(4096) | NO | | NULL | |
| serviceList | varchar(4096) | YES | | NULL | |
| startTime | varchar(32) | NO | | NULL | |
| stopTime | varchar(32) | NO | | NULL | |
±-----------------±--------------±-----±----±--------±---------------+
11 rows in set (0.00 sec)

When I try to delete a record, I get this:

Delete Maintenance Record - OID = 100
Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘AND “startTime” = ‘1/2/3333 1:23’ AND “stopTime” = ‘1/2/3333 1:24’’ at line 1
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘AND “startTime” = ‘1/2/3333 1:23’ AND “stopTime” = ‘1/2/3333 1:24’’ at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

So I went in an rebuilt the database and deleted the last 3 columns and repopulated it with exactly the same data (minus the serviceList which is always NULL at the moment, and the start/stop time fields. I then tried to delete a record and it worked just fine…

To make a long story short, I have tried building the database with various columns in/out (and sideways :)) and the result seems to be that if the serviceList column has a value of NULL, then the delete fails. If the serviceList column is not null, the delete succeeds.

Note that the serviceList column is allowed to be NULL - does that cause problems for the SQLContainer?
Is there something obvious that I’m missing here, or something I’m doing wrong in using the container? Or have I stumbled over a bug in the implementation?

At least I have a workaround now - I can force a dummy value into that column of the table and then it should work…

thanks for any pointers you can pass along…

nbc

Hi Neil,

Your problem sure does seem like a bug in the SQLContainer implementation, I created
a ticket
for the issue. It might have something to do with applying all filters even though only the ID is necessary, as you mentioned.

For future reference, you can call SQLContainer.setDebugMode(true) to make the SQLGenerators print debugging messages, including the queries being executed. I’d appreciate if you’d run your scenario with debugging turned on and add a comment with the query being run to
the ticket
.

Thanks,
/Jonatan

Thanks very much - I’ll try to re-run that code tomorrow with debug turned on and I’ll copy the output to the ticket.

And it is good to know that debug will show the query it tried to execute… Much obliged,

nbc