💻 Code Examples
Practical examples and real-world scenarios for using the Beep Data Management Engine
Examples below include a signature-verified API block sourced from current implementations in Editor/UOW, DataView, Caching, and Proxy.
Examples are now also organized by dedicated pages: Editor Classes Examples and Runtime Surfaces Examples.
Signature-Verified API Snippets
// UnitofWork<T>
public Task<IErrorsInfo> InsertAsync(T doc);
public Task<IErrorsInfo> UpdateAsync(T doc);
public Task<IErrorsInfo> DeleteAsync(T doc);
public Task<IErrorsInfo> Commit();
// MultiDataSourceUnitOfWork
public Task AddUnitOfWorkAsync<T>(string dataSourceName, string entityName, string primaryKey) where T : Entity, new();
public void AddRelationship(string parentEntityName, string childEntityName, string parentKeyField,
string childForeignKeyField, RelationshipBehavior deleteBehavior = RelationshipBehavior.CascadeDelete, bool isRequired = false);
public Task<IErrorsInfo> CommitAsync();
// DataViewDataSource
public partial class DataViewDataSource : IDataSource, IDataViewOperations, IDisposable;
// Caching
public interface ICacheProvider : IDisposable;
public static partial class CacheManager;
// Proxy
public interface IProxyDataSource : IDataSource, IDisposable;
📚 Table of Contents
🛒 Basic Customer Management System
This example shows how to create a complete customer management system using UnitOfWork.
CustomerManager Class
using TheTechIdea.Beep.Editor;
using TheTechIdea.Beep.DataBase;
public class CustomerManager
{
private readonly IDMEEditor _dmeEditor;
private UnitofWork<Customer> _customerUoW;
public CustomerManager(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
InitializeUnitOfWork();
}
private void InitializeUnitOfWork()
{
_customerUoW = new UnitofWork<Customer>(_dmeEditor, "SqlServer", "Customers", "CustomerID");
// Subscribe to events
_customerUoW.PreInsert += ValidateCustomerBeforeInsert;
_customerUoW.PostEdit += LogPropertyChanges;
_customerUoW.PreCommit += ValidateBeforeCommit;
}
public async Task<ObservableBindingList<Customer>> LoadCustomersAsync()
{
return await _customerUoW.Get();
}
public async Task<Customer> CreateNewCustomerAsync(string name, string email, string phone)
{
_customerUoW.New();
var customer = _customerUoW.CurrentItem;
customer.Name = name;
customer.Email = email;
customer.Phone = phone;
customer.CreatedDate = DateTime.Now;
customer.Status = "Active";
var result = await _customerUoW.InsertAsync(customer);
if (result.Flag == Errors.Ok)
{
return customer;
}
throw new Exception($"Failed to create customer: {result.Message}");
}
public async Task<bool> UpdateCustomerAsync(Customer customer)
{
customer.ModifiedDate = DateTime.Now;
var result = await _customerUoW.UpdateAsync(customer);
return result.Flag == Errors.Ok;
}
public async Task<bool> DeleteCustomerAsync(string customerId)
{
var customer = _customerUoW.Get(customerId);
if (customer != null)
{
var result = await _customerUoW.DeleteAsync(customer);
return result.Flag == Errors.Ok;
}
return false;
}
public async Task<bool> CommitAllChangesAsync()
{
if (_customerUoW.IsDirty)
{
var result = await _customerUoW.Commit();
return result.Flag == Errors.Ok;
}
return true;
}
// Event handlers
private void ValidateCustomerBeforeInsert(object sender, UnitofWorkParams args)
{
var customer = (Customer)sender;
if (string.IsNullOrWhiteSpace(customer.Name))
{
args.Cancel = true;
throw new ValidationException("Customer name is required");
}
if (string.IsNullOrWhiteSpace(customer.Email))
{
args.Cancel = true;
throw new ValidationException("Customer email is required");
}
}
private void LogPropertyChanges(object sender, UnitofWorkParams args)
{
var customer = (Customer)sender;
Console.WriteLine($"Customer {customer.CustomerID}: {args.PropertyName} changed to {args.PropertyValue}");
}
private void ValidateBeforeCommit(object sender, UnitofWorkParams args)
{
// Perform final validation before commit
var addedCustomers = _customerUoW.GetAddedEntities();
foreach (var index in addedCustomers)
{
var customer = _customerUoW.Units[index];
if (string.IsNullOrWhiteSpace(customer.Email) || !customer.Email.Contains("@"))
{
args.Cancel = true;
throw new ValidationException($"Invalid email for customer: {customer.Name}");
}
}
}
public void Dispose()
{
_customerUoW?.Dispose();
}
}
- Event-driven validation using PreInsert and PreCommit events
- Property change logging with PostEdit event
- Async operations for better performance
- Proper error handling and resource disposal
ðŸ›ï¸ Multi-DataSource E-Commerce System
This example demonstrates managing an e-commerce system with customers in SQL Server and orders in MongoDB.
ECommerceManager Class
public class ECommerceManager
{
private readonly IDMEEditor _dmeEditor;
private MultiDataSourceUnitOfWork _multiUoW;
public ECommerceManager(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
InitializeMultiDataSource();
}
private async Task InitializeMultiDataSource()
{
_multiUoW = new MultiDataSourceUnitOfWork(_dmeEditor);
// Add entity types from different data sources
await _multiUoW.AddUnitOfWorkAsync<Customer>("SqlServer", "Customers", "CustomerID");
await _multiUoW.AddUnitOfWorkAsync<Order>("MongoDB", "Orders", "OrderID");
await _multiUoW.AddUnitOfWorkAsync<Product>("SqlServer", "Products", "ProductID");
await _multiUoW.AddUnitOfWorkAsync<OrderItem>("MongoDB", "OrderItems", "OrderItemID");
// Define relationships
_multiUoW.AddRelationship("Customer", "Order", "CustomerID", "CustomerID",
RelationshipBehavior.CascadeDelete);
_multiUoW.AddRelationship("Order", "OrderItem", "OrderID", "OrderID",
RelationshipBehavior.CascadeDelete, true);
_multiUoW.AddRelationship("Product", "OrderItem", "ProductID", "ProductID",
RelationshipBehavior.Restrict);
// Subscribe to child data changes
_multiUoW.ChildDataChanged += OnChildDataChanged;
}
public async Task<string> CreateOrderAsync(string customerId, List<OrderItemData> items)
{
try
{
// Create new order
var order = new Order
{
OrderID = Guid.NewGuid().ToString(),
CustomerID = customerId,
OrderDate = DateTime.Now,
Status = "Pending",
TotalAmount = 0
};
await _multiUoW.InsertAsync("Order", order);
// Add order items
decimal totalAmount = 0;
foreach (var itemData in items)
{
var orderItem = new OrderItem
{
OrderItemID = Guid.NewGuid().ToString(),
OrderID = order.OrderID,
ProductID = itemData.ProductID,
Quantity = itemData.Quantity,
UnitPrice = itemData.UnitPrice,
TotalPrice = itemData.Quantity * itemData.UnitPrice
};
await _multiUoW.InsertAsync("OrderItem", orderItem);
totalAmount += orderItem.TotalPrice;
}
// Update order total
order.TotalAmount = totalAmount;
await _multiUoW.UpdateAsync("Order", order);
// Commit all changes
var result = await _multiUoW.CommitAsync();
if (result.Flag == Errors.Ok)
{
return order.OrderID;
}
throw new Exception($"Failed to create order: {result.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Error creating order: {ex.Message}");
throw;
}
}
public async Task<CustomerOrderView> GetCustomerWithOrdersAsync(string customerId)
{
// Get customer
var customers = _multiUoW.GetEntities<Customer>("Customer");
var customer = customers.FirstOrDefault(c => c.CustomerID == customerId);
if (customer == null)
return null;
// Navigate to customer to load related data
await _multiUoW.NavigateToParentAsync("Customer", customer);
// Get related orders
var relatedData = await _multiUoW.GetAllRelatedChildrenAsync<Order, Customer>("Customer", customer);
var orders = relatedData.ContainsKey("Order") ? relatedData["Order"] : new ObservableBindingList<Order>();
return new CustomerOrderView
{
Customer = customer,
Orders = orders.ToList()
};
}
public async Task<bool> CancelOrderAsync(String orderId)
{
try
{
var orders = _multiUoW.GetEntities<Order>("Order");
var order = orders.FirstOrDefault(o => o.OrderID == orderId);
if (order == null)
return false;
if (order.Status == "Shipped" || order.Status == "Delivered")
{
throw new InvalidOperationException("Cannot cancel shipped or delivered orders");
}
// Delete order (will cascade to order items)
await _multiUoW.DeleteAsync("Order", order);
var result = await _multiUoW.CommitAsync();
return result.Flag == Errors.Ok;
}
catch (Exception ex)
{
Console.WriteLine($"Error cancelling order: {ex.Message}");
return false;
}
}
private async void OnChildDataChanged(object sender, ChildDataChangedEventArgs args)
{
Console.WriteLine($"Child data changed: {args.ParentEntityName} → {args.ChildEntityName}");
// Update UI or perform other actions
if (args.ChildEntityName == "Order")
{
await RefreshOrderDisplay();
}
else if (args.ChildEntityName == "OrderItem")
{
await RefreshOrderItemDisplay();
}
}
public void Dispose()
{
_multiUoW?.Dispose();
}
}
// Supporting classes
public class OrderItemData
{
public string ProductID { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}
public class CustomerOrderView
{
public Customer Customer { get; set; }
public List<Order> Orders { get; set; }
}
- Cross-database relationships between SQL Server and MongoDB
- Automatic relationship management with cascade operations
- Event-driven UI updates when related data changes
- Transaction consistency across multiple data sources
🔄 Data Synchronization Between Systems
This example shows how to synchronize data between different systems with conflict resolution.
DataSynchronizer Class
public class DataSynchronizer
{
private readonly IDMEEditor _dmeEditor;
private UnitofWork<Product> _sourceUoW;
private UnitofWork<Product> _targetUoW;
public DataSynchronizer(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
InitializeUnitOfWorks();
}
private void InitializeUnitOfWorks()
{
// Source system (e.g., ERP)
_sourceUoW = new UnitofWork<Product>(_dmeEditor, "ERPSystem", "Products", "ProductID");
// Target system (e.g., E-commerce)
_targetUoW = new UnitofWork<Product>(_dmeEditor, "ECommerceDB", "Products", "ProductID");
}
public async Task<SyncResult> SynchronizeProductsAsync(DateTime? lastSyncDate = null)
{
var result = new SyncResult();
try
{
// Get products from source system
var filters = new List<AppFilter>();
if (lastSyncDate.HasValue)
{
filters.Add(new AppFilter
{
FieldName = "ModifiedDate",
Operator = ">",
FilterValue = lastSyncDate.Value
});
}
var sourceProducts = await _sourceUoW.Get(filters);
var targetProducts = await _targetUoW.Get();
foreach (var sourceProduct in sourceProducts)
{
var targetProduct = targetProducts.FirstOrDefault(p => p.ProductID == sourceProduct.ProductID);
if (targetProduct == null)
{
// Insert new product
await InsertProductAsync(sourceProduct, result);
}
else if (sourceProduct.ModifiedDate > targetProduct.ModifiedDate)
{
// Update existing product
await UpdateProductAsync(sourceProduct, targetProduct, result);
}
}
// Handle deletions (products in target but not in source)
var deletedProducts = targetProducts.Where(tp =>
!sourceProducts.Any(sp => sp.ProductID == tp.ProductID)).ToList();
foreach (var deletedProduct in deletedProducts)
{
await DeleteProductAsync(deletedProduct, result);
}
// Commit all changes
var commitResult = await _targetUoW.Commit();
if (commitResult.Flag == Errors.Ok)
{
result.Success = true;
result.Message = "Synchronization completed successfully";
}
else
{
result.Success = false;
result.Message = $"Commit failed: {commitResult.Message}";
await _targetUoW.Rollback();
}
}
catch (Exception ex)
{
result.Success = false;
result.Message = $"Synchronization failed: {ex.Message}";
await _targetUoW.Rollback();
}
return result;
}
public async Task<SyncResult> SynchronizeWithConflictResolutionAsync()
{
var result = new SyncResult();
try
{
var sourceProducts = await _sourceUoW.Get();
var targetProducts = await _targetUoW.Get();
foreach (var sourceProduct in sourceProducts)
{
var targetProduct = targetProducts.FirstOrDefault(p => p.ProductID == sourceProduct.ProductID);
if (targetProduct == null)
{
await InsertProductAsync(sourceProduct, result);
}
else
{
// Conflict resolution logic
var conflictResolution = ResolveConflict(sourceProduct, targetProduct);
switch (conflictResolution)
{
case ConflictResolution.UseSource:
await UpdateProductAsync(sourceProduct, targetProduct, result);
break;
case ConflictResolution.UseTarget:
// Keep target, do nothing
break;
case ConflictResolution.Merge:
var mergedProduct = MergeProducts(sourceProduct, targetProduct);
await UpdateProductAsync(mergedProduct, targetProduct, result);
break;
case ConflictResolution.Manual:
result.Conflicts.Add(new DataConflict
{
ProductID = sourceProduct.ProductID,
SourceProduct = sourceProduct,
TargetProduct = targetProduct
});
break;
}
}
}
if (result.Conflicts.Any())
{
result.Success = false;
result.Message = $"Synchronization completed with {result.Conflicts.Count} conflicts requiring manual resolution";
}
else
{
var commitResult = await _targetUoW.Commit();
result.Success = commitResult.Flag == Errors.Ok;
result.Message = result.Success ? "Synchronization completed successfully" : $"Commit failed: {commitResult.Message}";
}
}
catch (Exception ex)
{
result.Success = false;
result.Message = $"Synchronization failed: {ex.Message}";
await _targetUoW.Rollback();
}
return result;
}
private ConflictResolution ResolveConflict(Product source, Product target)
{
// Simple rule: if source is newer, use source
if (source.ModifiedDate > target.ModifiedDate)
return ConflictResolution.UseSource;
// If target is newer, check for manual intervention
if (target.ModifiedDate > source.ModifiedDate.AddHours(1))
return ConflictResolution.Manual;
return ConflictResolution.UseTarget;
}
public void Dispose()
{
_sourceUoW?.Dispose();
_targetUoW?.Dispose();
}
}
// Supporting classes
public class SyncResult
{
public bool Success { get; set; }
public string Message { get; set; }
public int InsertedCount { get; set; }
public int UpdatedCount { get; set; }
public int DeletedCount { get; set; }
public List<string> Errors { get; set; } = new List<string>();
public List<DataConflict> Conflicts { get; set; } = new List<DataConflict>();
}
public enum ConflictResolution
{
UseSource,
UseTarget,
Merge,
Manual
}
- UseSource: Source system data takes precedence
- UseTarget: Target system data is preserved
- Merge: Intelligent merging of both versions
- Manual: Requires human intervention to resolve
⚡ Batch Processing with Progress Reporting
This example demonstrates processing large datasets with progress reporting and error handling.
BatchProcessor Class
public class BatchProcessor
{
private readonly IDMEEditor _dmeEditor;
private UnitofWork<ImportRecord> _importUoW;
public event EventHandler<BatchProgressEventArgs> ProgressChanged;
public event EventHandler<BatchErrorEventArgs> ErrorOccurred;
public BatchProcessor(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
_importUoW = new UnitofWork<ImportRecord>(_dmeEditor, "DataWarehouse", "ImportRecords", "RecordID");
// Subscribe to events
_importUoW.PreInsert += ValidateRecord;
_importUoW.PostInsert += RecordInserted;
}
public async Task<BatchResult> ProcessBatchAsync(List<ImportData> data, CancellationToken cancellationToken = default)
{
var result = new BatchResult
{
TotalRecords = data.Count,
StartTime = DateTime.Now
};
var progress = new Progress<PassedArgs>(args => ReportProgress(args, result));
try
{
// Process in batches to avoid memory issues
const int batchSize = 1000;
var totalBatches = (int)Math.Ceiling((double)data.Count / batchSize);
for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
{
if (cancellationToken.IsCancellationRequested)
{
result.Status = BatchStatus.Cancelled;
break;
}
var batch = data.Skip(batchIndex * batchSize).Take(batchSize).ToList();
await ProcessSingleBatch(batch, batchIndex + 1, totalBatches, result, cancellationToken);
// Commit after each batch
var commitResult = await _importUoW.Commit(progress, cancellationToken);
if (commitResult.Flag != Errors.Ok)
{
result.Status = BatchStatus.Failed;
result.ErrorMessage = $"Commit failed for batch {batchIndex + 1}: {commitResult.Message}";
break;
}
// Clear processed records from memory
_importUoW.Clear();
}
if (result.Status == BatchStatus.InProgress)
{
result.Status = result.ErrorCount > 0 ? BatchStatus.CompletedWithErrors : BatchStatus.Completed;
}
}
catch (Exception ex)
{
result.Status = BatchStatus.Failed;
result.ErrorMessage = ex.Message;
}
finally
{
result.EndTime = DateTime.Now;
result.Duration = result.EndTime - result.StartTime;
}
return result;
}
private async Task ProcessSingleBatch(List<ImportData> batch, int batchNumber, int totalBatches,
BatchResult result, CancellationToken cancellationToken)
{
for (int i = 0; i < batch.Count; i++)
{
if (cancellationToken.IsCancellationRequested)
break;
try
{
var importData = batch[i];
var record = CreateImportRecord(importData, batchNumber);
await _importUoW.InsertAsync(record);
result.ProcessedRecords++;
}
catch (Exception ex)
{
result.ErrorCount++;
result.Errors.Add(new BatchError
{
BatchNumber = batchNumber,
RecordIndex = i,
Data = batch[i],
Error = ex.Message
});
ErrorOccurred?.Invoke(this, new BatchErrorEventArgs
{
BatchNumber = batchNumber,
RecordIndex = i,
Error = ex,
Message = $"Error processing record {i} in batch {batchNumber}"
});
}
// Report progress
if (i % 100 == 0 || i == batch.Count - 1)
{
ProgressChanged?.Invoke(this, new BatchProgressEventArgs
{
BatchNumber = batchNumber,
TotalBatches = totalBatches,
RecordsInBatch = batch.Count,
ProcessedInBatch = i + 1,
TotalProcessed = result.ProcessedRecords,
TotalRecords = result.TotalRecords,
ErrorCount = result.ErrorCount
});
}
}
}
public void Dispose()
{
_importUoW?.Dispose();
}
}
// Supporting classes
public class BatchResult
{
public int TotalRecords { get; set; }
public int ProcessedRecords { get; set; }
public int ErrorCount { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration { get; set; }
public BatchStatus Status { get; set; } = BatchStatus.InProgress;
public string ErrorMessage { get; set; }
public List<BatchError> Errors { get; set; } = new List<BatchError>();
}
public enum BatchStatus
{
InProgress,
Completed,
CompletedWithErrors,
Failed,
Cancelled
}
- Process data in manageable chunks to avoid memory issues
- Provide progress reporting for long-running operations
- Support cancellation tokens for user control
- Handle errors gracefully without stopping the entire batch
- Commit frequently to avoid transaction timeouts
🏗️ Complete Application Example
This example shows how to put it all together in a complete application.
Program.cs - Application Entry Point
public class Program
{
private static IDMEEditor _dmeEditor;
private static CustomerManager _customerManager;
private static ECommerceManager _ecommerceManager;
private static DataSynchronizer _dataSynchronizer;
public static async Task Main(string[] args)
{
try
{
// Initialize DME Editor
_dmeEditor = InitializeDMEEditor();
// Initialize managers
_customerManager = new CustomerManager(_dmeEditor);
_ecommerceManager = new ECommerceManager(_dmeEditor);
_dataSynchronizer = new DataSynchronizer(_dmeEditor);
// Run demo scenarios
await RunCustomerManagementDemo();
await RunECommerceDemo();
await RunDataSyncDemo();
Console.WriteLine("All demos completed successfully!");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
// Cleanup
_customerManager?.Dispose();
_ecommerceManager?.Dispose();
_dataSynchronizer?.Dispose();
_dmeEditor?.Dispose();
}
}
private static async Task RunCustomerManagementDemo()
{
Console.WriteLine("=== Customer Management Demo ===");
// Load existing customers
var customers = await _customerManager.LoadCustomersAsync();
Console.WriteLine($"Loaded {customers.Count} customers");
// Create new customer
var newCustomer = await _customerManager.CreateNewCustomerAsync(
"Demo Customer", "demo@example.com", "123-456-7890");
Console.WriteLine($"Created customer: {newCustomer.CustomerID}");
// Update customer
newCustomer.Phone = "098-765-4321";
await _customerManager.UpdateCustomerAsync(newCustomer);
Console.WriteLine("Customer updated");
// Commit changes
await _customerManager.CommitAllChangesAsync();
Console.WriteLine("Changes committed");
}
private static async Task RunECommerceDemo()
{
Console.WriteLine("\n=== E-Commerce Demo ===");
// Create an order
var orderItems = new List<OrderItemData>
{
new OrderItemData { ProductID = "PROD001", Quantity = 2, UnitPrice = 29.99m },
new OrderItemData { ProductID = "PROD002", Quantity = 1, UnitPrice = 49.99m }
};
var orderId = await _ecommerceManager.CreateOrderAsync "CUST001", orderItems);
Console.WriteLine($"Created order: {orderId}");
// Get customer with orders
var customerView = await _ecommerceManager.GetCustomerWithOrdersAsync("CUST001");
Console.WriteLine($"Customer {customerView.Customer.Name} has {customerView.Orders.Count} orders");
// Get pending orders
var pendingOrders = await _ecommerceManager.GetOrdersByStatusAsync("Pending");
Console.WriteLine($"Found {pendingOrders.Count} pending orders");
}
private static async Task RunDataSyncDemo()
{
Console.WriteLine("\n=== Data Synchronization Demo ===");
// Sync products
var syncResult = await _dataSynchronizer.SynchronizeProductsAsync(DateTime.Now.AddDays(-7));
Console.WriteLine($"Sync Result: {syncResult.Message}");
Console.WriteLine($"Inserted: {syncResult.InsertedCount}");
Console.WriteLine($"Updated: {syncResult.UpdatedCount}");
Console.WriteLine($"Deleted: {syncResult.DeletedCount}");
if (syncResult.Errors.Any())
{
Console.WriteLine("Errors:");
foreach (var error in syncResult.Errors)
{
Console.WriteLine($" - {error}");
}
}
}
private static IDMEEditor InitializeDMEEditor()
{
// Initialize using Autofac pattern
var builder = new ContainerBuilder();
// Register core services
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
var container = builder.Build();
var dmeEditor = container.Resolve();
// Initialize default configurations for IDataSource support
InitializeBeepDefaults(dmeEditor);
return dmeEditor;
}
}
- Modular design with separate managers for different concerns
- Proper dependency injection and resource management
- Comprehensive error handling and logging
- Demonstration of multiple advanced patterns
- Clean separation between data management and business logic
- Adapt entity classes (Customer, Order, Product) to match your data models
- Configure your data sources in the DMEEditor initialization
- Add proper error handling and logging for production use
- Consider using dependency injection for better testability
- Implement comprehensive unit tests for your business logic