Re: MySql AUTO_PK_SUPPORT

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Mon Apr 24 2006 - 09:41:56 EDT

  • Next message: Arnaud GARCIA: "ConcurrentModificationException ..."

    Borut,

    I don't have time to do serious review, but looks ok from the first
    glance.

    > How do I use this class, once we agree on the correct behaviour?

    Just set it on adapter. E.g.:

    import org.objectstyle.cayenne.property.PropertyUtils;
    DbAdapter adapter = ..

    // since DbAdapter doesn't define 'setPkGenerator',
    // but all implementors do, you can use introspection:
    PropertyUtils.setProperty(adapter, "pkGenerator", new
    MyJdbcPkGenerator());

    Andrus

    On Apr 24, 2006, at 3:11 PM, Borut Bolčina wrote:

    > Hi,
    >
    > as I need this functionality really bad (production code in three
    > weeks), I came up with this class. It is in a state we love to
    > call: "It compiles.". Can you please review it? How do I use this
    > class, once we agree on the correct behaviour?
    >
    > public class MyJdbcPkGenerator extends JdbcPkGenerator {
    >
    > /* (non-Javadoc)
    > *..ee org.objectstyle.cayenne.dba.JdbcPkGenerator#createAutoPk
    > (org.objectstyle.cayenne.access.DataNode, java.util.List)
    > */
    > ..verride
    > public void createAutoPk(DataNode node, List dbEntities) throws
    > Exception {
    > // check if a table exists
    >
    > // create AUTO_PK_SUPPORT table
    > if (!autoPkTableExists(node)) {
    > runUpdate(node, pkTableCreateString());
    > }
    >
    > // will hold only entities to be added to AUTO_PK_SUPPORT table
    > List<DbEntity> targetDbEntities = new ArrayList<DbEntity>();
    > // create a set of model entity names
    > Set<String> modelDbEntities = new HashSet<String>();
    > for (Iterator iter = dbEntities.iterator(); iter.hasNext();) {
    > DbEntity dbEntity = (DbEntity) iter.next();
    > modelDbEntities.add(dbEntity.getName());
    > }
    > // create a set of existing entity names (already in db)
    > Set<String> existingDbEntities = getExistingTables(node);
    > if (modelDbEntities.size() >= existingDbEntities.size()) {
    > // new tables added in modeler after database creation
    > modelDbEntities.removeAll(existingDbEntities);
    > // modelDbEntities now contains only entity names to be
    > added to AUTO_PK_SUPPORT table
    > for (String dbEntityName : modelDbEntities) {
    > targetDbEntities.add(new DbEntity
    > (dbEntityName)); }
    > dbEntities = targetDbEntities;
    > }
    > // TODO if (model < existing) then existing.removeAll
    > (model) then delete
    > // TODO if (model={T1, T2} and existing={T3, T4}) then insert
    > T1,T2 and delete T3,T4
    > // delete any existing pk entries
    > // runUpdate(node, pkDeleteString(dbEntities));
    >
    > // insert all needed entries
    > Iterator it = dbEntities.iterator();
    > while (it.hasNext()) {
    > DbEntity ent = (DbEntity) it.next();
    > runUpdate(node, pkCreateString(ent.getName()));
    > }
    > super.createAutoPk(node, dbEntities);
    > }
    >
    > protected Set<String> getExistingTables(DataNode node) throws
    > SQLException {
    > Set<String> existingTables = new HashSet<String>();
    > Connection con = node.getDataSource().getConnection();
    > Statement stmt = con.createStatement();
    > String query = "SELECT 'TABLE_NAME' FROM AUTO_PK_SUPPORT";
    > try {
    > ResultSet rs = stmt.executeQuery(query);
    > try {
    > while (rs.next()) {
    > String s = rs.getString("TABLE_NAME");
    > existingTables.add(s);
    > }
    > } finally {
    > rs.close();
    > }
    > } finally {
    > con.close();
    > }
    > return existingTables;
    > }
    > }
    >
    >
    > Regards,
    > Borut
    >
    > On 23.4.2006 11:34, Andrus Adamchik wrote:
    >>
    >> On Apr 23, 2006, at 1:21 PM, Borut Bolčina wrote:
    >>
    >>> If I understand you correctly, the above algorithm would create a
    >>> statement
    >>> DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ('tableA',
    >>> 'tableB', 'tableC')
    >>> but not, say, tableD, as it is already present (created before).
    >>>
    >>> In my case this pkDeleteString would look like (empty table names)
    >>> DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ('')
    >>> INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('', 200)
    >>
    >> Sorry, my first message and the correction that followed was a bit
    >> confusing. "DELETE FROM .." is not needed at all. You need to do a
    >> SELECT to see what's there, compare with the full entity list, and
    >> only insert the missing records.
    >>
    >> Also see Mike's suggestion on how to figure out the right starting
    >> value. It may work as an alternative or an addition to the
    >> algorithm above.
    >>
    >>
    >>> One "workaround" I can think of is to do a SELECT on
    >>> AUTO_PK_SUPPORT and if no error is thrown I must assume the table
    >>> exists, so I skip generator.runGenerator(dataSource); altogether.
    >>
    >> This is not generic enough as you may end up with missing records
    >> if you added a few new tables since the last run (so
    >> AUTO_PK_SUPPORT is there, but its contents are incomplete).
    >>
    >> Andrus
    >
    >
    >



    This archive was generated by hypermail 2.0.0 : Mon Apr 24 2006 - 09:42:23 EDT