جداول موقت در Oracle APEX

مفهوم جداول موقت در APEX

 

در این مقاله به یکی از بخش‌های جالب و نه‌چندان واضح در برنامه‌های Oracle APEX یعنی جداول موقت پرداخته می‌شود. در ادامه، خود جداول، نحوه کار با آن‌ها و موارد استفاده آن‌ها بررسی خواهد شد.

استفاده از جداول موقت برای توسعه‌دهندگان Oracle موضوع جدیدی نیست. این جدول‌ها معمولاً برای نگهداری داده‌ها در طول یک  session یا یک تراکنش خاص استفاده می‌شوند. اما Oracle برای توسعه‌دهندگان APEX نیز راهکاری اختصاصی در نظر گرفته که کار با داده‌های موقتی را بسیار ساده‌تر کرده است.

هدف اصلی استفاده از جداول موقت در APEX ذخیره داده‌ها تا زمانی‌ست که session کاربر فعال باشد؛ این قابلیت برای جلوگیری از از بین رفتن داده‌ها در زمان بارگذاری مجدد صفحه یا در سناریوهایی مانند سبد خرید بسیار کاربردی‌ست.

دو جدول موقت عمومی که در APEX وجود دارد:

  • APEX_COLLECTIONS
  • APEX_APPLICATION_TEMP_FILES

نکته قابل توجه این است که این جدول‌ها در واقع به صورت فیزیکی «موقت» نیستند، بلکه Viewهایی هستند که فیلتر آن‌ها بر اساس SESSION_ID اعمال شده است. همچنین باید در اعطای دسترسی به اسکیمای APEX_* بسیار محتاط بود.

جدول APEX_COLLECTIONS

Oracle یک API کامل برای کار با این جدول طراحی کرده که شامل:

  • View: APEX_COLLECTIONS
  • پکیج: APEX_COLLECTION

ساختار این جدول به‌گونه‌ای طراحی شده تا نیازهای متنوع توسعه‌دهندگان را پوشش دهد؛ برای همین دارای ۵۰ ستون VARCHAR2، پنج ستون NUMBER، پنج ستون DATE، یک ستون XMLTYPE، یک ستون BLOB و یک ستون CLOB است.

ایجاد کالکشن (Collection)

مثال‌هایی از روش‌های مختلف برای ساخت کالکشن

declare
l_collection_name CONSTANT VARCHAR2(20) := ‘DEMO_COLLECTION’;
l_exists BOOLEAN;
begin
— Approach 1
l_exists := APEX_COLLECTION.COLLECTION_EXISTS (p_collection_name => l_collection_name);
if l_exists = false then
APEX_COLLECTION.CREATE_COLLECTION(
p_collection_name    => l_collection_name,
p_truncate_if_exists => ‘NO’);
end if;

— Approach 2
APEX_COLLECTION.CREATE_COLLECTION(
p_collection_name    => l_collection_name,
p_truncate_if_exists => ‘YES’);
— OR
APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION(
p_collection_name    => l_collection_name);

— Approach 3
begin
APEX_COLLECTION.CREATE_COLLECTION(
p_collection_name    => l_collection_name,
p_truncate_if_exists => ‘NO’);
exception
when others then
null;
end;
end;

declare
l_collection_name CONSTANT VARCHAR2(20) := ‘DEMO_COLLECTION’;
l_seq NUMBER;
begin
l_seq := APEX_COLLECTION.ADD_MEMBER (
p_collection_name => l_collection_name,
p_c001 => ‘Text 1’,
p_c002 => ‘Text 2’,
p_c050 => ‘Text 50’,
p_n001 => 12345);

APEX_COLLECTION.UPDATE_MEMBER (
p_collection_name => l_collection_name,
p_seq             => l_seq,
p_c001            => ‘Modified text’);

APEX_COLLECTION.DELETE_MEMBER (
p_collection_name => l_collection_name,
p_seq             => l_seq);
end;

مشاهده داده‌های کالکشن

SELECT SEQ_ID, C001, C002, C050, N001
FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = ‘DEMO_COLLECTION’

همچنین داده‌های کالکشن را می‌توان از طریق Session Viewer در محیط APEX نیز مشاهده کرد.

 

 

ساختار داخلی APEX_COLLECTIONS

در واقع APEX_COLLECTIONS یک View غیرقابل ویرایش است که بر اساس View سیستم داخلی WWV_FLOW_COLLECTIONS ساخته شده. این View اطلاعات را از جدول‌های زیر می‌گیرد:

  • WWV_FLOW_COLLECTIONS$
  • WWV_FLOW_COLLECTION_MEMBERS$

و فقط داده‌هایی را نشان می‌دهد که متعلق به نشست جاری کاربر باشند. اطلاعاتی مانند FLOW_ID، COLLECTION_NAME، تاریخ ایجاد، و گروه امنیتی در آن ذخیره می‌شود.

 

select c.collection_name, m.seq_id, m.c001, m.c002, m.c003, m.c004, m.c005, m.c006, m.c007,
m.c008, m.c009, m.c010, m.c011, m.c012, m.c013, m.c014, m.c015, m.c016, m.c017,
m.c018, m.c019, m.c020, m.c021, m.c022, m.c023, m.c024, m.c025, m.c026, m.c027,
m.c028, m.c029, m.c030, m.c031, m.c032, m.c033, m.c034, m.c035, m.c036, m.c037,
m.c038, m.c039, m.c040, m.c041, m.c042, m.c043, m.c044, m.c045, m.c046, m.c047,
m.c048, m.c049, m.c050, m.clob001, m.blob001, m.xmltype001, m.n001, m.n002, m.n003,
m.n004, m.n005, m.d001, m.d002, m.d003, m.d004, m.d005, m.md5_original
from wwv_flow_current_sgid_for_dml sgid,
wwv_flow_collections$ c,
wwv_flow_collection_members$ m
where c.session_id = (select v(‘SESSION’) from sys.dual)
and c.security_group_id = sgid.security_group_id
and m.security_group_id = sgid.security_group_id
and c.id = m.collection_id
and c.flow_id = (select nv(‘FLOW_ID’) from sys.dual)

Also description of wwv_flow_collections$ table

Name               Null?    Type
—————— ——– ————-
ID                 NOT NULL NUMBER
SESSION_ID         NOT NULL NUMBER
USER_ID            NOT NULL VARCHAR2(255)
FLOW_ID            NOT NULL NUMBER
COLLECTION_NAME    NOT NULL VARCHAR2(255)
COLLECTION_CHANGED NOT NULL VARCHAR2(10)
CREATED_ON         NOT NULL DATE
SECURITY_GROUP_ID  NOT NULL NUMBER

جدول APEX_APPLICATION_TEMP_FILES

این جدول بیشتر برای مدیریت فایل‌های آپلودی در APEX استفاده می‌شود. ساختار آن ساده بوده و شامل فیلدهایی مانند:

Name           Null?    Type
————– ——– ————-
ID             NOT NULL NUMBER
APPLICATION_ID NOT NULL NUMBER
NAME           NOT NULL VARCHAR2(400)
FILENAME                VARCHAR2(400)
MIME_TYPE               VARCHAR2(255)
CREATED_ON              DATE
BLOB_CONTENT            BLOB

مثالی از آپلود فایل

در آیتم صفحه با نوع File Upload و تنظیم نوع ذخیره‌سازی روی APEX_APPLICATION_TEMP_FILES:

پس از انتخاب فایل، با اجرای Submit فایل در این جدول ذخیره می‌شود. اگر گزینه “Purge File at End of Request” فعال باشد، فایل بلافاصله پس از پایان درخواست حذف خواهد شد.

 

 

 

declare
l_cnt NUMBER := 0;
begin

APEX_DEBUG.ENABLE(apex_debug.c_log_level_info);

select count(1)
into l_cnt
from APEX_APPLICATION_TEMP_FILES;

APEX_DEBUG.INFO (p_message => ‘APEX_APPLICATION_TEMP_FILES has ‘ || l_cnt || ‘ row(s)’);

APEX_DEBUG.DISABLE;
end;

Result are under Debug tab in session info

Some Technical Stuff 🙂
Not surprised that APEX_APPLICATION_TEMP_FILES also public synonym that referred to WWV_FLOW_TEMP_FILES view. The source query for it

select id,
flow_id            application_id,
name,
filename,
mime_type,
created_on,
blob_content
from wwv_flow_current_sgid_for_dml sgid,
wwv_flow_file_objects$      a
where a.security_group_id = sgid.security_group_id
and session_id = ( select nv(‘SESSION’) from sys.dual )
with check option

And description for wwv_flow_file_objects$ table

Name              Null?    Type
—————– ——– ————–
ID                NOT NULL NUMBER
FLOW_ID           NOT NULL NUMBER
NAME              NOT NULL VARCHAR2(400)
PATHID                     NUMBER
FILENAME                   VARCHAR2(400)
TITLE                      VARCHAR2(255)
MIME_TYPE                  VARCHAR2(255)
DOC_SIZE                   NUMBER
DAD_CHARSET                VARCHAR2(128)
CREATED_BY                 VARCHAR2(255)
CREATED_ON                 DATE
UPDATED_BY                 VARCHAR2(255)
UPDATED_ON                 DATE
DELETED_AS_OF     NOT NULL DATE
LAST_UPDATED               DATE
CONTENT_TYPE               VARCHAR2(128)
BLOB_CONTENT               BLOB
LANGUAGE                   VARCHAR2(30)
DESCRIPTION                VARCHAR2(4000)
SECURITY_GROUP_ID          NUMBER
FILE_TYPE                  VARCHAR2(255)
FILE_CHARSET               VARCHAR2(128)
SESSION_ID                 NUMBER

You can see that pretty much useful information stored alongside with file, that can be used.

جمع‌بندی

Oracle با طراحی این جداول موقت در APEX، ابزار قدرتمند و ساده‌ای برای مدیریت داده‌های نشست در اختیار توسعه‌دهندگان قرار داده است. این قابلیت نه تنها انعطاف‌پذیر است، بلکه حرفه‌ای‌ترین روش برای ذخیره و مدیریت داده‌های موقتی در برنامه‌های APEX به شمار می‌رود.