Working with Virtual Fields and Custom Base Views
Virtual fields allow you to extend entities with computed or related data without modifying the underlying table structure. MemberJunction supports two primary approaches for implementing virtual fields through custom base views.
Overview
Virtual fields are calculated or derived fields that appear alongside regular entity fields in views, forms, and filters. They don't exist as physical columns in your database tables but are computed dynamically through SQL views or business logic.
Common use cases include:
- Displaying related field values from linked entities
- Performing calculations across related records
- Aggregating data from child records
- Computing derived values based on business rules
Types of Virtual Fields
1. Related Field Values
These fields pull values from related entities through foreign key relationships.
Example: Adding an IsSubscription
field to ContractTermLineItem
that displays the subscription status from the linked Product
record.
-- In your custom base view
SELECT
ctli.*,
p.IsSubscription
FROM ContractTermLineItem ctli
LEFT JOIN Product p ON ctli.ProductID = p.ID
2. Calculated Fields
These fields perform computations, often involving aggregations from related records.
Examples:
AnnualContractValue
: SUM of allAmount
values from relatedContractTermLineItem
recordsAnnualRecurringRevenue
: SUM ofAmount
values whereIsSubscription
is trueCurrentTermStart
/CurrentTermEnd
: Dates from the active contract term
-- Example aggregation in custom base view
SELECT
c.*,
ISNULL(line_items.AnnualContractValue, 0) as AnnualContractValue,
ISNULL(subscription_items.AnnualRecurringRevenue, 0) as AnnualRecurringRevenue
FROM Contract c
LEFT JOIN (
SELECT
ContractID,
SUM(Amount) as AnnualContractValue
FROM ContractTermLineItem
GROUP BY ContractID
) line_items ON c.ID = line_items.ContractID
LEFT JOIN (
SELECT
ctli.ContractID,
SUM(ctli.Amount) as AnnualRecurringRevenue
FROM ContractTermLineItem ctli
INNER JOIN Product p ON ctli.ProductID = p.ID
WHERE p.IsSubscription = 1
GROUP BY ctli.ContractID
) subscription_items ON c.ID = subscription_items.ContractID
Implementation Steps
Step 1: Create or Modify the Base View
You have two options for implementing custom base views:
Option A: Modify Existing Generated View
- Locate the existing base view (e.g.,
finance.vwContracts
) - Modify the view definition to include your virtual fields
- Update the
Entity
record in MemberJunction
Option B: Create New Custom View (Recommended)
- Create a new view with a descriptive name (e.g.,
finance.vwContracts_Custom
) - Include all original fields plus your virtual fields
- Update the
Entity
record to reference the new view
Recommended approach: Option B provides better maintainability and preserves the original generated view.
Step 2: Update Entity Configuration
- Navigate to the
Entity
record for your target entity - Update the
BaseView
field to reference your custom view name - Set
BaseViewGenerated = 0
to prevent MemberJunction from overwriting your custom view - Save the changes
Step 3: Run CodeGen
Execute the CodeGen process to regenerate the entity classes and metadata:
# Run CodeGen to update entity definitions
npm run codegen
This will:
- Generate new TypeScript/JavaScript classes with your virtual fields
- Update GraphQL schema definitions
- Refresh metadata for the MemberJunction Explorer
Step 4: Verify Implementation
After running CodeGen:
- Check that virtual fields appear in entity forms
- Verify fields are available as columns in list views
- Confirm fields can be used in filters and searches
- Test that calculated values display correctly
Best Practices
Naming Conventions
- Use descriptive names that clearly indicate the field's purpose
- Consider prefixing calculated fields (e.g.,
Calc_AnnualValue
) - Maintain consistency with existing field naming patterns
Performance Considerations
- Index Related Tables: Ensure foreign key columns used in JOINs are properly indexed
- Limit Aggregations: Complex calculations can impact view performance
- Consider Materialized Views: For frequently accessed calculated data
- Test with Production Data Volumes: Verify performance with realistic data sizes
View Structure
-- Template for custom base view
CREATE OR ALTER VIEW [schema].[vwEntityName_Custom] AS
SELECT
-- Original entity fields
base.*,
-- Related field values
related.FieldName as VirtualFieldName,
-- Calculated fields
calculations.CalculatedValue,
-- Conditional logic
CASE
WHEN condition THEN value1
ELSE value2
END as ConditionalField
FROM OriginalTable base
LEFT JOIN RelatedTable related ON base.RelatedID = related.ID
LEFT JOIN (
-- Subquery for calculations
SELECT
ParentID,
SUM(Amount) as CalculatedValue
FROM ChildTable
GROUP BY ParentID
) calculations ON base.ID = calculations.ParentID
Error Handling
- Use
ISNULL()
orCOALESCE()
to handle null values in calculations - Test edge cases where related records might not exist
- Consider default values for calculated fields
Troubleshooting
Common Issues
Virtual fields not appearing in UI
- Verify CodeGen completed successfully
- Check that
BaseViewGenerated = 0
in the Entity record - Confirm the custom view exists and is accessible
Performance problems
- Review execution plans for complex calculations
- Consider adding appropriate indexes
- Evaluate whether calculations should be moved to business logic
Incorrect calculations
- Test SQL queries independently before implementing
- Verify JOIN conditions and GROUP BY clauses
- Check for data type compatibility issues
Validation Steps
- Query the custom view directly to verify results
- Check entity metadata in MemberJunction Explorer
- Test field behavior in various UI contexts
- Validate calculated values against expected results
Advanced Scenarios
Dynamic Calculations
For calculations that change frequently or require complex business logic, consider implementing them in custom business logic classes rather than SQL views.
Cross-Entity References
Virtual fields can reference data from multiple related entities, but be mindful of performance implications with complex JOIN operations.
Conditional Display
Use CASE statements to create virtual fields that display different values based on business rules or entity states.
Virtual fields provide powerful capabilities for extending your MemberJunction entities without modifying database schema. By following these guidelines and best practices, you can implement robust calculated and related fields that integrate seamlessly with the MemberJunction platform.
Updated 16 days ago