diff --git a/migration/iD11/oracle/202305231609_IDEMPIERE-5567.sql b/migration/iD11/oracle/202305231609_IDEMPIERE-5567.sql new file mode 100644 index 0000000000..d2c2d4098e --- /dev/null +++ b/migration/iD11/oracle/202305231609_IDEMPIERE-5567.sql @@ -0,0 +1,88 @@ +-- IDEMPIERE-5567 Support of UUID as Key (FHCA-4195) +SELECT register_migration_script('202305231609_IDEMPIERE-5567.sql') FROM dual; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- May 23, 2023, 4:09:37 PM CEST +INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (215841,0,'Record UUID',200000,'Record_UU',36,'N','N','N','N','N',0,'N',200240,0,0,'Y',TO_TIMESTAMP('2023-05-23 16:09:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-05-23 16:09:37','YYYY-MM-DD HH24:MI:SS'),100,203804,'N','N','D','N','N','N','N','e4000430-78d0-42f3-bb99-d4cf8d32df5f','N','N','N','M','N') +; + +-- May 23, 2023, 4:09:45 PM CEST +ALTER TABLE AD_RecentItem ADD Record_UU VARCHAR2(36 CHAR) DEFAULT NULL +; + + +SET SERVEROUTPUT on; + +-- Set Record_UU for existing records +DECLARE + cmd varchar2(2000); + v_cnt numeric; +BEGIN + FOR r IN ( + SELECT DISTINCT t.TableName, ri.AD_Table_ID + FROM AD_RecentItem ri + JOIN AD_Table t ON (ri.AD_Table_ID=t.AD_Table_ID) + WHERE ri.Record_UU IS NULL + AND ri.Record_ID IS NOT NULL + ) LOOP + cmd := 'UPDATE AD_RecentItem SET Record_UU=(SELECT ' + || r.TableName + || '_UU FROM ' + || r.TableName + || ' WHERE ' + || r.TableName + || '_ID=AD_RecentItem.Record_ID) WHERE AD_Table_ID=' + || r.AD_Table_ID + || ' AND Record_ID IS NOT NULL AND Record_UU IS NULL'; + EXECUTE IMMEDIATE cmd; + DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' AD_RecentItem.Record_UU set in ' || r.TableName); + END LOOP; +END; +/ + +-- May 23, 2023, 7:17:27 PM CEST +DROP INDEX AD_RecentItem_Record_ID_AD_Table_ID +; + +-- May 23, 2023, 7:17:34 PM CEST +UPDATE AD_TableIndex SET Name='AD_RecentItem_Record_UU_AD_Table_ID',Updated=TO_TIMESTAMP('2023-05-23 19:17:34','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_TableIndex_ID=201116 +; + +-- May 23, 2023, 7:17:39 PM CEST +UPDATE AD_IndexColumn SET AD_Column_ID=215841,Updated=TO_TIMESTAMP('2023-05-23 19:17:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_IndexColumn_ID=201489 +; + +-- May 23, 2023, 7:17:44 PM CEST +CREATE INDEX AD_RecentItem_Record_UU_AD_Table_ID ON AD_RecentItem (Record_UU,AD_Table_ID) +; + +-- May 23, 2023, 7:18:09 PM CEST +INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,TableIndexDrop,IsKey) VALUES (0,0,201248,'3247c587-b7fb-4b66-93a5-ad05d386e0c5',TO_TIMESTAMP('2023-05-23 19:18:08','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','AD_RecentItem_AD_User_ID',TO_TIMESTAMP('2023-05-23 19:18:08','YYYY-MM-DD HH24:MI:SS'),100,200000,'N','N','N','N','N') +; + +-- May 23, 2023, 7:18:19 PM CEST +INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201687,'a10d5fdb-351f-4798-a4d8-4e5f3de4995b',TO_TIMESTAMP('2023-05-23 19:18:17','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 19:18:17','YYYY-MM-DD HH24:MI:SS'),100,200006,201248,10) +; + +-- May 23, 2023, 7:18:27 PM CEST +INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201688,'a06c4a1d-b923-479c-9415-e2d049e2ac90',TO_TIMESTAMP('2023-05-23 19:18:27','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 19:18:27','YYYY-MM-DD HH24:MI:SS'),100,200000,201248,20) +; + +-- May 23, 2023, 7:18:32 PM CEST +CREATE INDEX AD_RecentItem_AD_User_ID ON AD_RecentItem (AD_User_ID,AD_Client_ID) +; + +-- May 26, 2023, 7:30:07 PM CEST +UPDATE AD_Column SET IsMandatory='N', IsToolbarButton='N',Updated=TO_TIMESTAMP('2023-05-26 19:30:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=200011 +; + +-- May 26, 2023, 7:30:10 PM CEST +ALTER TABLE AD_RecentItem MODIFY Record_ID NUMBER(10) DEFAULT NULL +; + +-- May 26, 2023, 7:30:10 PM CEST +ALTER TABLE AD_RecentItem MODIFY Record_ID NULL +; + diff --git a/migration/iD11/postgresql/202305231609_IDEMPIERE-5567.sql b/migration/iD11/postgresql/202305231609_IDEMPIERE-5567.sql new file mode 100644 index 0000000000..0d41d70357 --- /dev/null +++ b/migration/iD11/postgresql/202305231609_IDEMPIERE-5567.sql @@ -0,0 +1,87 @@ +-- IDEMPIERE-5567 Support of UUID as Key (FHCA-4195) +SELECT register_migration_script('202305231609_IDEMPIERE-5567.sql') FROM dual; + +-- May 23, 2023, 4:09:37 PM CEST +INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (215841,0,'Record UUID',200000,'Record_UU',36,'N','N','N','N','N',0,'N',200240,0,0,'Y',TO_TIMESTAMP('2023-05-23 16:09:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-05-23 16:09:37','YYYY-MM-DD HH24:MI:SS'),100,203804,'N','N','D','N','N','N','N','e4000430-78d0-42f3-bb99-d4cf8d32df5f','N','N','N','M','N') +; + +-- May 23, 2023, 4:09:45 PM CEST +ALTER TABLE AD_RecentItem ADD COLUMN Record_UU VARCHAR(36) DEFAULT NULL +; + + +-- Set Record_UU for existing records +DO $$ +DECLARE + cmd varchar(2000); + r record; + v_cnt numeric; +BEGIN + FOR r IN + SELECT DISTINCT t.TableName, ri.AD_Table_ID + FROM AD_RecentItem ri + JOIN AD_Table t ON (ri.AD_Table_ID=t.AD_Table_ID) + WHERE ri.Record_UU IS NULL + AND ri.Record_ID IS NOT NULL + LOOP + cmd := 'UPDATE AD_RecentItem SET Record_UU=(SELECT ' + || r.TableName + || '_UU FROM ' + || r.TableName + || ' WHERE ' + || r.TableName + || '_ID=AD_RecentItem.Record_ID) WHERE AD_Table_ID=' + || r.AD_Table_ID + || ' AND Record_ID IS NOT NULL AND Record_UU IS NULL'; + EXECUTE cmd; + GET DIAGNOSTICS v_cnt = ROW_COUNT; + RAISE NOTICE '% AD_RecentItem.Record_UU set in %', v_cnt, r.TableName; + END LOOP; +END; +$$ +; + +-- May 23, 2023, 7:17:27 PM CEST +DROP INDEX AD_RecentItem_Record_ID_AD_Table_ID +; + +-- May 23, 2023, 7:17:34 PM CEST +UPDATE AD_TableIndex SET Name='AD_RecentItem_Record_UU_AD_Table_ID',Updated=TO_TIMESTAMP('2023-05-23 19:17:34','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_TableIndex_ID=201116 +; + +-- May 23, 2023, 7:17:39 PM CEST +UPDATE AD_IndexColumn SET AD_Column_ID=215841,Updated=TO_TIMESTAMP('2023-05-23 19:17:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_IndexColumn_ID=201489 +; + +-- May 23, 2023, 7:17:44 PM CEST +CREATE INDEX AD_RecentItem_Record_UU_AD_Table_ID ON AD_RecentItem (Record_UU,AD_Table_ID) +; + +-- May 23, 2023, 7:18:09 PM CEST +INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,TableIndexDrop,IsKey) VALUES (0,0,201248,'3247c587-b7fb-4b66-93a5-ad05d386e0c5',TO_TIMESTAMP('2023-05-23 19:18:08','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','AD_RecentItem_AD_User_ID',TO_TIMESTAMP('2023-05-23 19:18:08','YYYY-MM-DD HH24:MI:SS'),100,200000,'N','N','N','N','N') +; + +-- May 23, 2023, 7:18:19 PM CEST +INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201687,'a10d5fdb-351f-4798-a4d8-4e5f3de4995b',TO_TIMESTAMP('2023-05-23 19:18:17','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 19:18:17','YYYY-MM-DD HH24:MI:SS'),100,200006,201248,10) +; + +-- May 23, 2023, 7:18:27 PM CEST +INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201688,'a06c4a1d-b923-479c-9415-e2d049e2ac90',TO_TIMESTAMP('2023-05-23 19:18:27','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 19:18:27','YYYY-MM-DD HH24:MI:SS'),100,200000,201248,20) +; + +-- May 23, 2023, 7:18:32 PM CEST +CREATE INDEX AD_RecentItem_AD_User_ID ON AD_RecentItem (AD_User_ID,AD_Client_ID) +; + +-- May 26, 2023, 7:30:07 PM CEST +UPDATE AD_Column SET IsMandatory='N', IsToolbarButton='N',Updated=TO_TIMESTAMP('2023-05-26 19:30:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=200011 +; + +-- May 26, 2023, 7:30:10 PM CEST +INSERT INTO t_alter_column values('ad_recentitem','Record_ID','NUMERIC(10)',null,'NULL') +; + +-- May 26, 2023, 7:30:10 PM CEST +INSERT INTO t_alter_column values('ad_recentitem','Record_ID',null,'NULL',null) +; + diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_RecentItem.java b/org.adempiere.base/src/org/compiere/model/I_AD_RecentItem.java index f0ab018068..fcba30e862 100644 --- a/org.adempiere.base/src/org/compiere/model/I_AD_RecentItem.java +++ b/org.adempiere.base/src/org/compiere/model/I_AD_RecentItem.java @@ -197,6 +197,15 @@ public interface I_AD_RecentItem */ public int getRecord_ID(); + /** Column name Record_UU */ + public static final String COLUMNNAME_Record_UU = "Record_UU"; + + /** Set Record UUID */ + public void setRecord_UU (String Record_UU); + + /** Get Record UUID */ + public String getRecord_UU(); + /** Column name Updated */ public static final String COLUMNNAME_Updated = "Updated"; diff --git a/org.adempiere.base/src/org/compiere/model/MRecentItem.java b/org.adempiere.base/src/org/compiere/model/MRecentItem.java index ea654be388..6825d41d10 100644 --- a/org.adempiere.base/src/org/compiere/model/MRecentItem.java +++ b/org.adempiere.base/src/org/compiere/model/MRecentItem.java @@ -13,9 +13,7 @@ *****************************************************************************/ package org.compiere.model; -import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -26,13 +24,12 @@ import java.util.logging.Level; import org.adempiere.base.Core; import org.adempiere.base.event.EventManager; -import org.adempiere.exceptions.AdempiereException; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Util; -import org.idempiere.cache.ImmutablePOSupport; import org.idempiere.cache.ImmutablePOCache; +import org.idempiere.cache.ImmutablePOSupport; import org.idempiere.distributed.IMessageService; import org.idempiere.distributed.ITopic; import org.osgi.service.event.Event; @@ -47,7 +44,7 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport /** * */ - private static final long serialVersionUID = -6564296810614189111L; + private static final long serialVersionUID = 4298877865937943663L; public static final String ON_RECENT_ITEM_CHANGED_TOPIC = "onRecentItemChanged"; @@ -80,6 +77,12 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport super (ctx, AD_RecentItem_ID, trxName); } // MRecentItem + /** + * Get the cache key AD_RecentItem_ID|Language + * @param AD_RecentItem_ID + * @param ctx + * @return + */ private static String getCacheKey(int AD_RecentItem_ID, Properties ctx) { return AD_RecentItem_ID + "|" + Env.getAD_Language(ctx); } @@ -169,17 +172,17 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport * Get Recent Item from Cache using table+recordID (immutable) * @param ctx context * @param AD_Table_ID tableID - * @param Record_ID recordID + * @param Record_UU record UUID * @return recent item */ - public static synchronized MRecentItem get (Properties ctx, int AD_Table_ID, int Record_ID, int AD_User_ID) + public static synchronized MRecentItem get (Properties ctx, int AD_Table_ID, String Record_UU, int AD_User_ID) { Iterator it = s_cache.values().iterator(); while (it.hasNext()) { MRecentItem retValue = it.next(); if (retValue.getAD_Table_ID() == AD_Table_ID - && retValue.getRecord_ID() == Record_ID + && retValue.getRecord_UU().equals(Record_UU) && retValue.getAD_User_ID() == AD_User_ID && retValue.getAD_Client_ID() == Env.getAD_Client_ID(ctx) && Env.getAD_Language(ctx).equals(Env.getAD_Language(retValue.getCtx())) @@ -189,30 +192,9 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport } } // - MRecentItem retValue = null; - String sql = "SELECT * FROM AD_RecentItem WHERE AD_Table_ID=? AND Record_ID=? AND NVL(AD_User_ID,0)=? AND AD_Client_ID=?"; - PreparedStatement pstmt = null; - ResultSet rs = null; - try - { - pstmt = DB.prepareStatement (sql, null); - pstmt.setInt(1, AD_Table_ID); - pstmt.setInt(2, Record_ID); - pstmt.setInt(3, AD_User_ID); - pstmt.setInt(4, Env.getAD_Client_ID(ctx)); - rs = pstmt.executeQuery (); - if (rs.next ()) - retValue = new MRecentItem (ctx, rs, null); - } catch (SQLException e) { - e.printStackTrace(); - throw new AdempiereException(e); - } - finally - { - DB.close(rs, pstmt); - rs = null; pstmt = null; - } - + MRecentItem retValue = new Query(ctx, Table_Name, "AD_Table_ID=? AND Record_UU=? AND AD_User_ID=? AND AD_Client_ID=?", null) + .setParameters(AD_Table_ID, Record_UU, AD_User_ID, Env.getAD_Client_ID(ctx)) + .first(); if (retValue != null) { String key = getCacheKey(retValue.getAD_RecentItem_ID(), ctx); @@ -221,19 +203,28 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport return retValue; } // get - /* + /** * addModifiedField / method to be called when first field is modified on a window * it adds a record in recent item, or touches the record if it was added before + * @param ctx + * @param AD_Table_ID + * @param Record_ID + * @param Record_UU + * @param AD_User_ID + * @param AD_Role_ID + * @param AD_Window_ID + * @param AD_Tab_ID */ - public static void addModifiedField(Properties ctx, int AD_Table_ID, int Record_ID, int AD_User_ID, int AD_Role_ID, int AD_Window_ID, int AD_Tab_ID) { + public static void addModifiedField(Properties ctx, int AD_Table_ID, int Record_ID, String Record_UU, int AD_User_ID, int AD_Role_ID, int AD_Window_ID, int AD_Tab_ID) { int maxri = MSysConfig.getIntValue(MSysConfig.RecentItems_MaxSaved, 50, Env.getAD_Client_ID(ctx)); if (maxri <= 0) return; - MRecentItem ric = get(ctx, AD_Table_ID, Record_ID, AD_User_ID); + MRecentItem ric = get(ctx, AD_Table_ID, Record_UU, AD_User_ID); if (ric == null) { MRecentItem ri = new MRecentItem(ctx, 0, null); ri.setAD_Table_ID(AD_Table_ID); ri.setRecord_ID(Record_ID); + ri.setRecord_UU(Record_UU); ri.setAD_User_ID(AD_User_ID); ri.setAD_Role_ID(AD_Role_ID); ri.setAD_Window_ID(AD_Window_ID); @@ -265,6 +256,9 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport publishChangedEvent(AD_User_ID); } + /** + * @param AD_User_ID + */ public static void publishChangedEvent(int AD_User_ID) { IMessageService service = Core.getMessageService(); if (service != null) { @@ -275,6 +269,9 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport } } + /** + * @param AD_User_ID + */ public static void postOnChangedEvent(int AD_User_ID) { Map properties = new HashMap(); properties.put("AD_User_ID", AD_User_ID); @@ -282,13 +279,17 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport EventManager.getInstance().postEvent(event); } - /* + /** * touchUpdatedRecord / method to be called when a record is saved or updated in database * it touches the record added before * also delete recent items beyond the number of records allowed per user + * @param ctx + * @param AD_Table_ID + * @param Record_UU + * @param AD_User_ID */ - public static void touchUpdatedRecord(Properties ctx, int AD_Table_ID, int Record_ID, int AD_User_ID) { - MRecentItem ri = get(ctx, AD_Table_ID, Record_ID, AD_User_ID); + public static void touchUpdatedRecord(Properties ctx, int AD_Table_ID, String Record_UU, int AD_User_ID) { + MRecentItem ri = get(ctx, AD_Table_ID, Record_UU, AD_User_ID); if (ri != null) { DB.executeUpdateEx("UPDATE AD_RecentItem SET Updated=getDate() WHERE AD_RecentItem_ID=?", new Object[] {ri.getAD_RecentItem_ID()}, null); deleteExtraRecentItems(ctx, AD_User_ID); @@ -296,53 +297,44 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport } } + /** + * Delete the recent items beyond the maximum number of records configured in SysConfig RecentItems_MaxSaved + * @param ctx + * @param AD_User_ID + */ private static void deleteExtraRecentItems(Properties ctx, int AD_User_ID) { int AD_Client_ID = Env.getAD_Client_ID(ctx); int maxri = MSysConfig.getIntValue(MSysConfig.RecentItems_MaxSaved, 50, AD_Client_ID); - if (maxri < 0) - maxri = 0; - int cntri = DB.getSQLValue(null, "SELECT COUNT(*) FROM AD_RecentItem WHERE NVL(AD_User_ID,0)=? AND AD_Client_ID=?", AD_User_ID, AD_Client_ID); - if (cntri > maxri) { - int cntdel = cntri - maxri; - String sql = "SELECT * FROM AD_RecentItem WHERE NVL(AD_User_ID,0)=? AND AD_Client_ID=? ORDER BY Updated"; - PreparedStatement pstmt = null; - ResultSet rs = null; - try - { - pstmt = DB.prepareStatement (sql, null); - pstmt.setInt(1, AD_User_ID); - pstmt.setInt(2, AD_Client_ID); - rs = pstmt.executeQuery (); - while (rs.next()) { - MRecentItem ri = new MRecentItem(ctx, rs, (String)null); - ri.deleteEx(true); - cntdel--; - if (cntdel == 0) - break; + if (maxri <= 0) + maxri = 50; + final String sql = "" + + "SELECT AD_RecentItem_ID FROM AD_RecentItem " + + "WHERE AD_User_ID=? AND AD_Client_ID=? AND AD_RecentItem_ID NOT IN ( " + + "SELECT AD_RecentItem_ID FROM AD_RecentItem WHERE AD_User_ID=? AND AD_Client_ID=? ORDER BY Updated DESC FETCH FIRST ? ROWS ONLY)"; + int ids[] = DB.getIDsEx(null, sql, AD_User_ID, AD_Client_ID, AD_User_ID, AD_Client_ID, maxri); + if (ids.length > 0) { + for (int id : ids) { + String ii = getCacheKey(id, ctx); + synchronized (MRecentItem.class) { + s_cache.remove(ii); } - } catch (SQLException e) { - e.printStackTrace(); - throw new AdempiereException(e); - } - finally - { - DB.close(rs, pstmt); - rs = null; pstmt = null; } + final String delete = "" + + "DELETE FROM AD_RecentItem " + + "WHERE AD_User_ID=? AND AD_Client_ID=? AND AD_RecentItem_ID NOT IN ( " + + "SELECT AD_RecentItem_ID FROM AD_RecentItem WHERE AD_User_ID=? AND AD_Client_ID=? ORDER BY Updated DESC FETCH FIRST ? ROWS ONLY)"; + DB.executeUpdateEx(delete, new Object[] {AD_User_ID, AD_Client_ID, AD_User_ID, AD_Client_ID, maxri}, null); } } - @Override - public boolean delete(boolean force) { - String ii = getCacheKey(getAD_RecentItem_ID(), getCtx()); - synchronized (MRecentItem.class) { - s_cache.remove(ii); - } - return super.delete(force); - } - + /** + * Get the recent items from user - for performance obtain the ids and then get the MRecentItem from cache + * @param ctx + * @param AD_User_ID + * @return + */ public static List getFromUser(Properties ctx, int AD_User_ID) { - int[] ids = new Query(ctx, MRecentItem.Table_Name, "NVL(AD_User_ID,0)=?", null) + int[] ids = new Query(ctx, MRecentItem.Table_Name, "AD_User_ID=?", null) .setOnlyActiveRecords(true) .setClient_ID() .setParameters(AD_User_ID) @@ -368,13 +360,13 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport windowName = win.get_Translation("Name"); } MTable table = MTable.get(getCtx(), getAD_Table_ID()); - PO po = table.getPO(getRecord_ID(), null); + PO po = table.getPOByUU(getRecord_UU(), null); if (po == null) { - /* Recent Item was deleted (probably with direct SQL DELETE) */ - if (is_Immutable()) - new MRecentItem(Env.getCtx(), this).deleteEx(true); - else - this.deleteEx(true, null); + String ii = getCacheKey(getAD_RecentItem_ID(), getCtx()); + synchronized (MRecentItem.class) { + s_cache.remove(ii); + } + DB.executeUpdateEx("DELETE FROM AD_RecentItem WHERE AD_RecentItem=?", new Object[] {getAD_RecentItem_ID()}, null); return null; } @@ -406,16 +398,24 @@ public class MRecentItem extends X_AD_RecentItem implements ImmutablePOSupport return m_label; } - public static synchronized void clearLabel(int AD_Table_ID, int Record_ID) { + /** + * Clear the label (to display) in a recent item + * @param AD_Table_ID + * @param Record_ID + */ + public static synchronized void clearLabel(int AD_Table_ID, String Record_UU) { Iterator it = s_cache.values().iterator(); while (it.hasNext()) { MRecentItem retValue = it.next(); - if (retValue.getAD_Table_ID() == AD_Table_ID && retValue.getRecord_ID() == Record_ID) { + if (retValue.getAD_Table_ID() == AD_Table_ID && retValue.getRecord_UU().equals(Record_UU)) { retValue.clearLabel(); } } } + /** + * Clear the label (to display) + */ private void clearLabel() { m_label = null; } diff --git a/org.adempiere.base/src/org/compiere/model/PO.java b/org.adempiere.base/src/org/compiere/model/PO.java index d88a963dda..202af4b43c 100644 --- a/org.adempiere.base/src/org/compiere/model/PO.java +++ b/org.adempiere.base/src/org/compiere/model/PO.java @@ -2690,7 +2690,7 @@ public abstract class PO m_createNew = false; } if (!newRecord) - MRecentItem.clearLabel(p_info.getAD_Table_ID(), get_ID()); + MRecentItem.clearLabel(p_info.getAD_Table_ID(), get_UUID()); if (CacheMgt.get().hasCache(p_info.getTableName())) { if (!newRecord) Adempiere.getThreadPoolExecutor().submit(() -> CacheMgt.get().reset(p_info.getTableName(), get_ID())); diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_RecentItem.java b/org.adempiere.base/src/org/compiere/model/X_AD_RecentItem.java index fa182616eb..98d7eaf023 100644 --- a/org.adempiere.base/src/org/compiere/model/X_AD_RecentItem.java +++ b/org.adempiere.base/src/org/compiere/model/X_AD_RecentItem.java @@ -30,7 +30,7 @@ public class X_AD_RecentItem extends PO implements I_AD_RecentItem, I_Persistent /** * */ - private static final long serialVersionUID = 20230409L; + private static final long serialVersionUID = 20230523L; /** Standard Constructor */ public X_AD_RecentItem (Properties ctx, int AD_RecentItem_ID, String trxName) @@ -309,4 +309,19 @@ public class X_AD_RecentItem extends PO implements I_AD_RecentItem, I_Persistent return 0; return ii.intValue(); } + + /** Set Record UUID. + @param Record_UU Record UUID + */ + public void setRecord_UU (String Record_UU) + { + set_ValueNoCheck (COLUMNNAME_Record_UU, Record_UU); + } + + /** Get Record UUID. + @return Record UUID */ + public String getRecord_UU() + { + return (String)get_Value(COLUMNNAME_Record_UU); + } } \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java index f9c43304cd..dbc4d09c51 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java @@ -2003,17 +2003,17 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements //update recent item if (changed && !readOnly && !toolbar.isSaveEnable() ) { - if (tabPanel.getGridTab().getRecord_ID() > 0) { + if (!Util.isEmpty(tabPanel.getGridTab().getRecord_UU())) { if (adTabbox.getSelectedIndex() == 0 && !detailTab) { MRecentItem.addModifiedField(ctx, adTabbox.getSelectedGridTab().getAD_Table_ID(), - adTabbox.getSelectedGridTab().getRecord_ID(), Env.getAD_User_ID(ctx), + adTabbox.getSelectedGridTab().getRecord_ID(), adTabbox.getSelectedGridTab().getRecord_UU(), Env.getAD_User_ID(ctx), Env.getAD_Role_ID(ctx), adTabbox.getSelectedGridTab().getAD_Window_ID(), adTabbox.getSelectedGridTab().getAD_Tab_ID()); } else { GridTab mainTab = getMainTabAbove(); if (mainTab != null) { MRecentItem.addModifiedField(ctx, mainTab.getAD_Table_ID(), - mainTab.getRecord_ID(), Env.getAD_User_ID(ctx), + mainTab.getRecord_ID(), mainTab.getRecord_UU(), Env.getAD_User_ID(ctx), Env.getAD_Role_ID(ctx), mainTab.getAD_Window_ID(), mainTab.getAD_Tab_ID()); } @@ -2264,7 +2264,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements focusToActivePanel(); // IDEMPIERE-1328 - refresh recent item after running a process, i.e. completing a doc that changes documentno MRecentItem.touchUpdatedRecord(ctx, adTabbox.getSelectedGridTab().getAD_Table_ID(), - adTabbox.getSelectedGridTab().getRecord_ID(), Env.getAD_User_ID(ctx)); + adTabbox.getSelectedGridTab().getRecord_UU(), Env.getAD_User_ID(ctx)); } /** @@ -2853,17 +2853,17 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements if (wasChanged) { if (newRecord) { - if (adTabbox.getSelectedGridTab().getRecord_ID() > 0) { + if (!Util.isEmpty(adTabbox.getSelectedGridTab().getRecord_UU())) { if (adTabbox.getSelectedIndex() == 0) { MRecentItem.addModifiedField(ctx, adTabbox.getSelectedGridTab().getAD_Table_ID(), - adTabbox.getSelectedGridTab().getRecord_ID(), Env.getAD_User_ID(ctx), + adTabbox.getSelectedGridTab().getRecord_ID(), adTabbox.getSelectedGridTab().getRecord_UU(), Env.getAD_User_ID(ctx), Env.getAD_Role_ID(ctx), adTabbox.getSelectedGridTab().getAD_Window_ID(), adTabbox.getSelectedGridTab().getAD_Tab_ID()); } else { GridTab mainTab = getMainTabAbove(); if (mainTab != null) { MRecentItem.addModifiedField(ctx, mainTab.getAD_Table_ID(), - mainTab.getRecord_ID(), Env.getAD_User_ID(ctx), + mainTab.getRecord_ID(), mainTab.getRecord_UU(), Env.getAD_User_ID(ctx), Env.getAD_Role_ID(ctx), mainTab.getAD_Window_ID(), mainTab.getAD_Tab_ID()); } @@ -2872,12 +2872,12 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements } else { if (adTabbox.getSelectedIndex() == 0) { MRecentItem.touchUpdatedRecord(ctx, adTabbox.getSelectedGridTab().getAD_Table_ID(), - adTabbox.getSelectedGridTab().getRecord_ID(), Env.getAD_User_ID(ctx)); + adTabbox.getSelectedGridTab().getRecord_UU(), Env.getAD_User_ID(ctx)); } else { GridTab mainTab = getMainTabAbove(); if (mainTab != null) { MRecentItem.touchUpdatedRecord(ctx, mainTab.getAD_Table_ID(), - mainTab.getRecord_ID(), Env.getAD_User_ID(ctx)); + mainTab.getRecord_UU(), Env.getAD_User_ID(ctx)); } } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java index c905059167..d33cee08d8 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java @@ -28,6 +28,7 @@ import org.compiere.model.MRecentItem; import org.compiere.model.MRole; import org.compiere.model.MSysConfig; import org.compiere.model.MTable; +import org.compiere.model.PO; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; @@ -230,11 +231,10 @@ public class DPRecentItems extends DashboardPanel implements EventListener 0) { + if ( AD_RecentItem_ID > 0) { MRecentItem ri = MRecentItem.get(Env.getCtx(), AD_RecentItem_ID); String TableName = MTable.getTableName(Env.getCtx(), ri.getAD_Table_ID()); - MQuery query = MQuery.getEqualQuery(TableName + "_ID", ri.getRecord_ID()); - + MQuery query = MQuery.getEqualQuery(PO.getUUIDColumnName(TableName), ri.getRecord_UU()); SessionManager.getAppDesktop().openWindow(ri.getAD_Window_ID(), query, null); } } @@ -269,7 +269,7 @@ public class DPRecentItems extends DashboardPanel implements EventListener 0 && MRole.getDefault().getWindowAccess(ri.getAD_Window_ID()) == null) continue; - if (ri.getAD_Window_ID() > 0 && !MRole.getDefault().isRecordAccess(ri.getAD_Table_ID(), ri.getRecord_ID(), true)) + if (ri.getAD_Window_ID() > 0 && ri.getRecord_ID() > 0 && !MRole.getDefault().isRecordAccess(ri.getAD_Table_ID(), ri.getRecord_ID(), true)) continue; String label = ri.getLabel();