Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Mastering One-to-Many Mappings with ILookup and Aspose Cell Generation

Tech May 13 2

Overview

The ILookup<TKey, TElement> interface offers a robust solution for managing hierarchical data structures where a single key maps to multiple values. Extending IEnumerable<T>, it inherits all LINQ capabilities while providing O(1) indexing performance. This approach is superior to standard Dictionaries or Lists when dealing with one-to-many relationships, such as grouping administratvie regions by their parent area.

Data Grouping Strategy

Consider a scenario where regional data must be categorized by province before exporting. The process begins by retrieving the source records. Once fetched, the code determines the object's metadata dynamically to facilitate reflection-based processing later.

var rawData = service.FetchHierarchy(regionId, categoryType, startTime, endTime);

if (rawData.Any())
{
    var itemTypeInfo = rawData.First().GetType();
    
    // Extract unique identifiers for the grouping key
    var uniqueKeys = rawData
        .Select(x => (string)itemTypeInfo.GetProperty("Name").GetValue(x))
        .Distinct()
        .ToList();

    // Construct the ILookup
    // Key: Province Name | Value: List of subordinate cities
    var lookupGrouping = uniqueKeys
        .Select(name => new { 
            Id = name,
            SubRegions = service.GetSubdivisions(name, regionId, categoryType, startTime, endTime)
        })
        .ToLookup(g => g.Id, p => p.SubRegions.ToList());

    // Trigger the export process
    ExcelExporter.SaveReport(
        $"export_{DateTime.Now:yyyyMMddHHmmss}.xls", 
        lookupGrouping, 
        new[] { "Region Name", "Population Count" }
    );
}
else
{
    throw new NullReferenceException("No data available for export.");
}

Workbook Processing Implementation

The core export logic iterates through each entry in the ILookup. Each group becomes a dedicated worksheet named after its primary key. Reflection is utilized within the rendering loop to populate cells dynamically based on the source object's properties rather than hardcoding fields.

public static void SaveReport<TItem>(string outputFileName, ILookup<string, List<TItem>> groups, params string[] headerCols) 
    where TItem : class
{
    Stream streamResult;
    using (var workbook = new Workbook())
    {
        workbook.Worksheets.Clear();

        foreach (var group in groups)
        {
            // Create a new sheet for each grouping key
            var sheet = workbook.Worksheets.Add(group.Key);
            
            // Ensure there are items to write
            if (group.Count > 0 && group.First()?.Count > 0)
            {
                RenderSheet(sheet, group.First(), headerCols);
            }
        }

        streamResult = workbook.SaveToStream();
    }

    FileHandler.WriteStream(outputFileName, streamResult);
}

private static void RenderSheet<TItem>(Worksheet targetSheet, IEnumerable<TItem> rows, string[] columns) 
    where TItem : class
{
    var dataList = rows.ToList();
    int totalRows = dataList.Count;
    
    if (totalRows == 0) return;

    var cellCollection = targetSheet.Cells;
    var propertyInfoArray = dataList[0].GetType().GetProperties();
    
    // Initialize Headers
    for (int colIndex = 0; colIndex < columns.Length; colIndex++)
    {
        cellCollection[0, colIndex].PutValue(columns[colIndex]);
    }

    // Iterate rows and map properties
    int startRowIndex = 1;
    for (int rowIndex = 0; rowIndex < totalRows; rowIndex++)
    {
        var currentItem = dataList[rowIndex];
        
        for (int propIndex = 0; propIndex < columns.Length; propIndex++)
        {
            var value = propertyInfoArray[propIndex].GetValue(currentItem);
            cellCollection[startRowIndex + rowIndex, propIndex].PutValue(value);
        }
    }
}

This architecture decouples data retrieval from presentation formatting. By utilizing ILookup, the application ensures that related entities remain grouped logically, simplifying the iteration logic required for complex multi-sheet exports.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.