TSQL.APP File Management Training
Introduction to File Management in TSQL.APP
TSQL.APP offers robust built-in functionality for file management, allowing you to easily upload, store, categorize, and display files within your application. This training covers the key concepts, components, and best practices for effective file management in TSQL.APP.
Table of Contents
- Database Structure for Files
- File Functions and Stored Procedures
- File Uploads in Forms
- Managing File Categories
- Practical Examples
- Common Errors and Solutions
Database Structure for Files
Main Tables
TSQL.APP stores file information in the following tables:
-
api_files: The main table for file information
id
: Unique identifier for the filefilename
: Original file namemimetype
: MIME type of the filefilesize
: Size in bytesdescription
: Optional descriptioncontext
: Application context (usually the table name)context_id
: ID of the related recordfile_category_id
: Reference to categorycreated
: Date/time of uploadcreated_by
: User who uploaded the file
-
api_file_category: Categories for files
id
: Unique identifier for the categoryname
: Category namedescription
: Optional description
Relationships and Constraints
- Each file in
api_files
is linked to a record in another table viacontext
andcontext_id
- Files can be categorized via the
file_category_id
foreign key - The physical files are stored in a file system, while the metadata is stored in the database
Important Query Examples
- Retrieve all files for a specific record:
SELECT f.id, f.filename, f.filesize, f.description, c.name AS category
FROM api_files f
LEFT JOIN api_file_category c ON f.file_category_id = c.id
WHERE f.context = 'your_table_name'
AND f.context_id = @record_id;
- Filter files by category:
SELECT f.id, f.filename, f.description
FROM api_files f
WHERE f.context = 'your_table_name'
AND f.context_id = @record_id
AND f.file_category_id = (SELECT id FROM api_file_category WHERE name = 'your_category');
File Functions and Stored Procedures
File Management Procedures
TSQL.APP provides various stored procedures for file management:
1. sp_sys_file_upload
Upload a file and attach it to a record.
Parameters:
@card_name
: Name of the card/table@id
: ID of the record@name
: Name for the file (can be different from the original file name)@user_name
: User uploading the file@mimetype
: MIME type of the file@modified
: Modification date (optional)@filesize
: File size (optional)@description
: File description (optional)@category
: File category (optional)@toast
: Show confirmation message (optional)
Example:
EXEC sp_sys_file_upload
@card_name = N'customers',
@id = 42,
@name = N'Contract Document',
@user_name = dbo.context_user(),
@category = N'contracts';
2. sp_sys_file_preview
Open a file preview view.
Parameters:
@card_name
: Name of the card/table@id
: ID of the record@file_id
: ID of the specific file (optional)@print
: Show print option (optional)@height
: Height of the preview (optional)
Example:
EXEC sp_sys_file_preview
@card_name = N'customers',
@id = 42,
@file_id = 123,
@print = 1;
3. sp_sys_file_delete
Delete a file.
Parameters:
@card_name
: Name of the card/table@id
: ID of the record@file_id
: ID of the file to delete@user_name
: Username for tracking
Example:
EXEC sp_sys_file_delete
@card_name = N'customers',
@id = 42,
@file_id = 123,
@user_name = dbo.context_user();
Modal UI Components for Files
1. sp_api_modal_file
Simple file uploader for a single file.
Parameters:
@name
: Name of the form control@to_file_context
: Context name (table)@to_file_context_id
: ID of the related record@description
: File description@api_files_id
: Output parameter for file ID@url
: Output parameter for file URL@use_placeholder
: Placeholder name (optional)@category
: File category (optional)@resize_max
: Maximum image size for resize (optional)@resize_quality
: Quality of resized images (optional)@filename
: Suggestion for file name (optional)
Example:
DECLARE @api_files_id INT;
DECLARE @url NVARCHAR(4000);
EXEC sp_api_modal_file
@name = N'ProfilePhoto',
@to_file_context = N'employees',
@to_file_context_id = @id,
@description = N'Employee profile photo',
@api_files_id = @api_files_id OUT,
@url = @url OUT,
@category = N'photos';
2. sp_api_modal_file_multi
Advanced multi-file uploader with drag-and-drop interface.
Parameters:
@name
: Name of the form control@to_file_context
: Context name (table)@to_file_context_id
: ID of the related record@description
: File description@api_files_ids
: Output parameter for file IDs (comma-separated)@files_ready_for_use
: Output parameter for readiness status@category
: File category (optional)@message
: Instruction message (optional)@filesize_limit
: Maximum file size (optional)@upload_finished
: Output parameter for completion status
Example:
DECLARE @api_files_ids NVARCHAR(MAX);
DECLARE @files_ready_for_use BIT;
DECLARE @upload_finished BIT;
EXEC sp_api_modal_file_multi
@name = N'InvoiceAttachments',
@to_file_context = N'invoices',
@to_file_context_id = @id,
@description = N'Invoice attachments',
@api_files_ids = @api_files_ids OUT,
@files_ready_for_use = @files_ready_for_use OUT,
@category = N'financial',
@message = N'Drop invoice files here or click to browse',
@upload_finished = @upload_finished OUT;
File Uploads in Forms
Single File Upload Pattern
-- 1. Declare necessary variables
DECLARE @api_files_id INT;
DECLARE @url NVARCHAR(4000);
DECLARE @upload_button NVARCHAR(MAX);
-- 2. Synchronize with modal state
EXEC sp_api_modal_get_value @name='@upload_button', @value=@upload_button OUT;
-- 3. Add file uploader component
EXEC sp_api_modal_text @text=N'Upload Document', @class=N'font-weight-bold';
EXEC sp_api_modal_file
@name = N'DocumentUpload',
@to_file_context = N'customers',
@to_file_context_id = @id,
@description = N'Customer document',
@api_files_id = @api_files_id OUT,
@url = @url OUT,
@category = N'documents';
-- 4. Process uploads
IF @api_files_id IS NOT NULL
BEGIN
EXEC sp_api_toast @text=N'Document successfully uploaded', @class=N'btn-success';
END
Multi-File Upload Pattern
-- 1. Declare necessary variables
DECLARE @api_files_ids NVARCHAR(MAX);
DECLARE @files_ready_for_use BIT;
DECLARE @upload_finished BIT;
-- 2. Synchronize with modal state
EXEC sp_api_modal_get_value @name='@api_files_ids', @value=@api_files_ids OUT;
EXEC sp_api_modal_get_value @name='@files_ready_for_use', @value=@files_ready_for_use OUT;
EXEC sp_api_modal_get_value @name='@upload_finished', @value=@upload_finished OUT;
-- 3. Add multi-file uploader component
EXEC sp_api_modal_text @text=N'Upload Project Files', @class=N'font-weight-bold';
EXEC sp_api_modal_file_multi
@name = N'ProjectFiles',
@to_file_context = N'projects',
@to_file_context_id = @id,
@description = N'Project files and documents',
@api_files_ids = @api_files_ids OUT,
@files_ready_for_use = @files_ready_for_use OUT,
@category = N'project_docs',
@message = N'Drop project files here or click to browse',
@upload_finished = @upload_finished OUT;
-- 4. Process uploads
IF @upload_finished = 1 AND @api_files_ids IS NOT NULL AND LEN(@api_files_ids) > 0
BEGIN
EXEC sp_api_toast @text=N'Project files successfully uploaded', @class=N'btn-success';
END
Managing File Categories
File categories are a powerful way to organize uploads within your TSQL.APP application. They allow you to separate different types of files, apply filtering, and implement different processing.
Defining Categories
Categories are stored in the api_file_category
table. They can be added via:
INSERT INTO api_file_category (name, description)
VALUES
(N'invoices', N'Invoice documents'),
(N'contracts', N'Contract documents'),
(N'photos', N'Photo attachments'),
(N'technical', N'Technical specifications');
Filtering Files by Category
The correct way to filter files by category:
-- Retrieving files in a specific category
SELECT f.*
FROM api_files f
WHERE f.context = 'customers'
AND f.context_id = @customer_id
AND f.file_category_id = (SELECT id FROM api_file_category WHERE name = 'contracts');
Checking and Creating Categories
Pattern for checking if a category exists (and creating it if needed):
DECLARE @category_id INT;
-- Find the category ID
SELECT @category_id = id
FROM api_file_category
WHERE name = N'your_category';
-- Create the category if it doesn't exist
IF @category_id IS NULL
BEGIN
INSERT INTO api_file_category (name, description)
VALUES (N'your_category', N'Description of your category');
SET @category_id = SCOPE_IDENTITY();
END
Practical Examples
Example 1: Invoice with Multi-Document Upload
-- Container form with file upload functionality
-- 1. Declare all variables at the beginning (TSQL.APP mandated practice)
DECLARE @invoice_number NVARCHAR(MAX);
DECLARE @invoice_date NVARCHAR(MAX);
DECLARE @amount DECIMAL(18,2);
DECLARE @description NVARCHAR(MAX);
DECLARE @input_button NVARCHAR(MAX);
DECLARE @Title NVARCHAR(MAX);
DECLARE @SubTitle NVARCHAR(MAX);
DECLARE @Message NVARCHAR(MAX);
DECLARE @api_files_ids NVARCHAR(MAX);
DECLARE @has_attachments BIT;
DECLARE @files_ready_for_use BIT;
DECLARE @upload_finished BIT;
DECLARE @file_description NVARCHAR(MAX);
-- 2. Synchronize with modal state
EXEC sp_api_modal_get_value @name='@invoice_number', @value=@invoice_number OUT;
EXEC sp_api_modal_get_value @name='@invoice_date', @value=@invoice_date OUT;
EXEC sp_api_modal_get_value @name='@amount', @value=@amount OUT;
EXEC sp_api_modal_get_value @name='@description', @value=@description OUT;
EXEC sp_api_modal_get_value @name='@input_button', @value=@input_button OUT;
EXEC sp_api_modal_get_value @name='@api_files_ids', @value=@api_files_ids OUT;
EXEC sp_api_modal_get_value @name='@files_ready_for_use', @value=@files_ready_for_use OUT;
EXEC sp_api_modal_get_value @name='@upload_finished', @value=@upload_finished OUT;
-- 3. Load existing data if available
IF @id > 0
BEGIN
SELECT
@invoice_number = ISNULL(@invoice_number, invoice_number),
@invoice_date = ISNULL(@invoice_date, CONVERT(NVARCHAR, invoice_date, 126)),
@amount = ISNULL(@amount, amount),
@description = ISNULL(@description, description)
FROM invoices
WHERE id = @id;
END
-- 4. Check if there are existing attachments
SELECT @has_attachments = CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END
FROM api_files
WHERE context = 'invoices'
AND context_id = @id
AND file_category_id = (SELECT id FROM api_file_category WHERE name = 'invoice_docs');
-- 5. Build the form
SET @Title = N'Invoice Details';
SET @SubTitle = N'Enter invoice details and add attachments';
SET @file_description = N'Invoice attachments';
-- Title
EXEC sp_api_modal_text @text=@Title, @class=N'h3';
EXEC sp_api_modal_text @text=@SubTitle, @class=N'text-muted';
-- Invoice details section
EXEC sp_api_modal_text @text=N'Invoice Details', @class=N'h5';
-- Invoice number
EXEC sp_api_modal_text @text=N'Invoice Number:', @class=N'font-weight-bold';
EXEC sp_api_modal_input
@name = N'@invoice_number',
@value = @invoice_number OUT,
@placeholder = N'Enter invoice number';
-- Invoice date
EXEC sp_api_modal_text @text=N'Invoice Date:', @class=N'font-weight-bold';
EXEC sp_api_modal_input_datetime
@name = N'@invoice_date',
@value = @invoice_date OUT;
-- Amount
EXEC sp_api_modal_text @text=N'Amount:', @class=N'font-weight-bold';
EXEC sp_api_modal_input_decimal
@name = N'@amount',
@value = @amount OUT,
@precision = 18,
@scale = 2;
-- Description
EXEC sp_api_modal_text @text=N'Description:', @class=N'font-weight-bold';
EXEC sp_api_modal_input
@name = N'@description',
@value = @description OUT,
@type = N'textarea',
@placeholder = N'Enter description';
-- Attachment section
EXEC sp_api_modal_text @text=N'Invoice Attachments', @class=N'h5 mt-4';
-- Show status if needed
IF @has_attachments = 1
BEGIN
EXEC sp_api_modal_text @text=N'There are attachments linked to this invoice', @class=N'text-success';
END
-- Multi-file uploader
EXEC sp_api_modal_file_multi
@name = N'InvoiceFiles',
@to_file_context = N'invoices',
@to_file_context_id = @id,
@description = @file_description,
@api_files_ids = @api_files_ids OUT,
@files_ready_for_use = @files_ready_for_use OUT,
@category = N'invoice_docs',
@message = N'Drop invoice attachments here or click to browse',
@upload_finished = @upload_finished OUT;
-- Show upload status if needed
IF @upload_finished = 1 AND @api_files_ids IS NOT NULL AND LEN(@api_files_ids) > 0
BEGIN
SET @Message = N'Attachments successfully uploaded.';
EXEC sp_api_modal_text @text=@Message, @class=N'text-success';
END
-- Horizontal line
EXEC sp_api_modal_text @text=N'<hr>', @class=N'mt-4 mb-4';
-- Save button
EXEC sp_api_modal_button
@name = N'@input_button',
@value = N'Save Invoice',
@valueout = @input_button OUT,
@class = N'btn-success',
@key = N'Enter';
-- 6. Process form submit
IF @input_button IS NOT NULL
BEGIN
-- Validation
IF @invoice_number IS NULL OR LEN(TRIM(@invoice_number)) = 0
BEGIN
SET @Message = N'Please enter a valid invoice number.';
EXEC sp_api_toast @text=@Message, @class=N'btn-warning';
RETURN;
END
IF @amount IS NULL OR @amount <= 0
BEGIN
SET @Message = N'Please enter a valid amount.';
EXEC sp_api_toast @text=@Message, @class=N'btn-warning';
RETURN;
END
-- Update or insert record
IF @id > 0
BEGIN
-- Update existing invoice
UPDATE invoices
SET invoice_number = @invoice_number,
invoice_date = CONVERT(DATE, @invoice_date),
amount = @amount,
description = @description,
last_updated = GETDATE()
WHERE id = @id;
END
ELSE
BEGIN
-- Add new invoice
INSERT INTO invoices (
invoice_number,
invoice_date,
amount,
description,
created_date,
last_updated
)
VALUES (
@invoice_number,
CONVERT(DATE, @invoice_date),
@amount,
@description,
GETDATE(),
GETDATE()
);
-- Get new ID for file context
SET @id = SCOPE_IDENTITY();
-- Update file context with new ID if files were uploaded
IF @api_files_ids IS NOT NULL AND LEN(@api_files_ids) > 0
BEGIN
UPDATE api_files
SET context_id = @id
WHERE id IN (SELECT value FROM STRING_SPLIT(@api_files_ids, ','))
AND context = 'invoices'
AND context_id IS NULL;
END
END
-- Show confirmation and close modal
SET @Message = N'Invoice successfully saved!';
EXEC sp_api_toast @text=@Message, @class=N'btn-success';
EXEC sp_api_modal_clear;
RETURN;
END
Example 2: Document Preview and Management
-- Document preview and management form
DECLARE @doc_title NVARCHAR(MAX);
DECLARE @doc_type NVARCHAR(MAX);
DECLARE @view_button NVARCHAR(MAX);
DECLARE @print_button NVARCHAR(MAX);
DECLARE @delete_button NVARCHAR(MAX);
DECLARE @back_button NVARCHAR(MAX);
DECLARE @Title NVARCHAR(MAX);
DECLARE @Message NVARCHAR(MAX);
DECLARE @file_id INT;
DECLARE @has_file BIT;
DECLARE @filename NVARCHAR(MAX);
-- Synchronize with modal state
EXEC sp_api_modal_get_value @name='@doc_title', @value=@doc_title OUT;
EXEC sp_api_modal_get_value @name='@doc_type', @value=@doc_type OUT;
EXEC sp_api_modal_get_value @name='@view_button', @value=@view_button OUT;
EXEC sp_api_modal_get_value @name='@print_button', @value=@print_button OUT;
EXEC sp_api_modal_get_value @name='@delete_button', @value=@delete_button OUT;
EXEC sp_api_modal_get_value @name='@back_button', @value=@back_button OUT;
EXEC sp_api_modal_get_value @name='@file_id', @value=@file_id OUT;
-- Retrieve document data
SELECT @doc_title = title,
@doc_type = document_type
FROM documents
WHERE id = @id;
-- Retrieve file data
SELECT TOP 1
@file_id = f.id,
@filename = f.filename,
@has_file = 1
FROM api_files f
WHERE f.context = 'documents'
AND f.context_id = @id
ORDER BY f.id DESC;
-- Build the form
SET @Title = N'Document Details';
-- Title
EXEC sp_api_modal_text @text=@Title, @class=N'h3';
-- Document information
EXEC sp_api_modal_text @text=N'Document Information', @class=N'h5';
-- Title
EXEC sp_api_modal_text @text=N'Title:', @class=N'font-weight-bold';
EXEC sp_api_modal_input
@name = N'@doc_title',
@value = @doc_title OUT,
@placeholder = N'Document title';
-- Type
EXEC sp_api_modal_text @text=N'Document Type:', @class=N'font-weight-bold';
EXEC sp_api_modal_input
@name = N'@doc_type',
@value = @doc_type OUT,
@placeholder = N'Document type';
-- File information section
EXEC sp_api_modal_text @text=N'File Information', @class=N'h5 mt-4';
IF @has_file = 1
BEGIN
-- Show file information
SET @Message = CONCAT(N'Current file: ', @filename);
EXEC sp_api_modal_text @text=@Message, @class=N'text-info';
-- Buttons section
EXEC sp_api_modal_text @text=N'File Actions', @class=N'h6 mt-3';
-- View button
EXEC sp_api_modal_button
@name = N'@view_button',
@value = N'View Document',
@valueout = @view_button OUT,
@class = N'btn-primary',
@inline = 1;
-- Print button
EXEC sp_api_modal_button
@name = N'@print_button',
@value = N'Print Document',
@valueout = @print_button OUT,
@class = N'btn-info',
@inline = 1;
-- Delete button
EXEC sp_api_modal_button
@name = N'@delete_button',
@value = N'Delete Document',
@valueout = @delete_button OUT,
@class = N'btn-danger',
@inline = 1;
END
ELSE
BEGIN
-- No file found message
EXEC sp_api_modal_text @text=N'No file linked to this document.', @class=N'text-warning';
-- Upload section
EXEC sp_api_modal_text @text=N'Upload Document', @class=N'h6 mt-3';
-- File uploader
DECLARE @api_files_id INT;
DECLARE @url NVARCHAR(4000);
EXEC sp_api_modal_file
@name = N'DocumentFile',
@to_file_context = N'documents',
@to_file_context_id = @id,
@description = @doc_title,
@api_files_id = @api_files_id OUT,
@url = @url OUT,
@category = N'document';
-- Show message if a file is uploaded
IF @api_files_id IS NOT NULL
BEGIN
SET @Message = N'Document successfully uploaded!';
EXEC sp_api_toast @text=@Message, @class=N'btn-success';
-- Refresh the page to show the new file
EXEC sp_api_modal_restart;
RETURN;
END
END
-- Horizontal line
EXEC sp_api_modal_text @text=N'<hr>', @class=N'mt-4 mb-4';
-- Back button
EXEC sp_api_modal_button
@name = N'@back_button',
@value = N'Back to List',
@valueout = @back_button OUT,
@class = N'btn-secondary';
-- Process button actions
IF @view_button IS NOT NULL
BEGIN
-- Open document preview
EXEC sp_sys_file_preview
@card_name = N'documents',
@id = @id,
@file_id = @file_id;
RETURN;
END
IF @print_button IS NOT NULL
BEGIN
-- Open document preview with print option
EXEC sp_sys_file_preview
@card_name = N'documents',
@id = @id,
@file_id = @file_id,
@print = 1;
RETURN;
END
IF @delete_button IS NOT NULL
BEGIN
-- Delete file
EXEC sp_sys_file_delete
@card_name = N'documents',
@id = @id,
@file_id = @file_id,
@user_name = dbo.context_user();
SET @Message = N'Document successfully deleted!';
EXEC sp_api_toast @text=@Message, @class=N'btn-success';
-- Refresh the page to show the updated status
EXEC sp_api_modal_restart;
RETURN;
END
IF @back_button IS NOT NULL
BEGIN
-- Go back to the document list
EXEC sp_api_modal_clear;
RETURN;
END
Common Errors and Solutions
1. Incorrect Category Filtering
Error:
-- INCORRECT: Direct reference to category name
SELECT * FROM api_files
WHERE context = 'customers'
AND context_id = @id
AND category = 'photos'; -- This column doesn't exist
Solution:
-- CORRECT: Use file_category_id with subquery
SELECT * FROM api_files
WHERE context = 'customers'
AND context_id = @id
AND file_category_id = (SELECT id FROM api_file_category WHERE name = 'photos');
2. Missing OUT Parameters
Error:
-- INCORRECT: Missing OUT parameters in sp_api_modal_file_multi
EXEC sp_api_modal_file_multi
@name = N'DocFiles',
@to_file_context = N'documents',
@to_file_context_id = @id,
@category = N'document'; -- Missing required OUT parameters
Solution:
-- CORRECT: All required OUT parameters
DECLARE @api_files_ids NVARCHAR(MAX);
DECLARE @files_ready_for_use BIT;
DECLARE @upload_finished BIT;
EXEC sp_api_modal_file_multi
@name = N'DocFiles',
@to_file_context = N'documents',
@to_file_context_id = @id,
@description = N'Document files',
@api_files_ids = @api_files_ids OUT,
@files_ready_for_use = @files_ready_for_use OUT,
@category = N'document',
@upload_finished = @upload_finished OUT;
3. Apostrophes in String Parameters
Error:
-- INCORRECT: Apostrophe in string literal
SET @message = N'Let's upload files'; -- This causes a syntax error
Solution:
-- CORRECT: Either double the apostrophes or avoid them
SET @message = N'Lets upload files';
-- Or
SET @message = N'Let''s upload files';
4. Missing Initialization of Upload Variables
Error:
-- INCORRECT: Using variables without initialization
IF @upload_finished = 1 AND @api_files_ids IS NOT NULL
BEGIN
-- Processing code
END
Solution:
-- CORRECT: Declare and synchronize all variables
DECLARE @api_files_ids NVARCHAR(MAX);
DECLARE @upload_finished BIT;
EXEC sp_api_modal_get_value @name='@api_files_ids', @value=@api_files_ids OUT;
EXEC sp_api_modal_get_value @name='@upload_finished', @value=@upload_finished OUT;
IF @upload_finished = 1 AND @api_files_ids IS NOT NULL
BEGIN
-- Processing code
END
5. Improper Context ID Handling for New Records
Error:
-- INCORRECT: Using @to_file_context_id = @id when @id is not set
EXEC sp_api_modal_file_multi
@name = N'Attachments',
@to_file_context = N'customers',
@to_file_context_id = @id, -- @id might be NULL for new records
@description = N'Customer attachments',
@api_files_ids = @api_files_ids OUT,
@files_ready_for_use = @files_ready_for_use OUT,
@category = N'attachments',
@upload_finished = @upload_finished OUT;
Solution:
-- CORRECT: Update context_id after insert for new records
IF @id IS NULL OR @id = 0
BEGIN
-- Insert the main record first
INSERT INTO customers (name, email) VALUES (@name, @email);
SET @id = SCOPE_IDENTITY();
-- Then update any uploaded files with the new ID
IF @api_files_ids IS NOT NULL AND LEN(@api_files_ids) > 0
BEGIN
UPDATE api_files
SET context_id = @id
WHERE id IN (SELECT value FROM STRING_SPLIT(@api_files_ids, ','))
AND context = 'customers'
AND context_id IS NULL;
END
END
By following these best practices and examples, you can effectively implement file management functionality in your TSQL.APP applications while avoiding common pitfalls and errors.