TBARPT.Library 1.5.7

dotnet add package TBARPT.Library --version 1.5.7
                    
NuGet\Install-Package TBARPT.Library -Version 1.5.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TBARPT.Library" Version="1.5.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TBARPT.Library" Version="1.5.7" />
                    
Directory.Packages.props
<PackageReference Include="TBARPT.Library" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TBARPT.Library --version 1.5.7
                    
#r "nuget: TBARPT.Library, 1.5.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TBARPT.Library@1.5.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TBARPT.Library&version=1.5.7
                    
Install as a Cake Addin
#tool nuget:?package=TBARPT.Library&version=1.5.7
                    
Install as a Cake Tool

Introduction

The purpose of this library is to enable Dynamic LINQ string construction and execution, as well as dynamically creating and executing queries using expression trees. This is intended to support specific applications local to our environment, though it may be useful to others. Helpers are also available for retrieving lists of properties, their types, and display names from a given type. Using ReflectionIgnore attribute will prevent a class from returing results, or individual properties from being included in the list of properties.

Getting Started

  1. Add this package and dependencies
  2. Example usage:

using TBARPT.Library.Attributes;
using TBARPT.Library.Models;
using TBARPT.Library.Service;

//The interface inherits from IReportMethodSource which will tell TBARPT library that this class can been scanned for report methods. 
//Methods that return IQueryable or QueryResult can be used as report methods, and the library will be able to execute them and return the results when requested.
public interface IExampleReportMethodSource : IReportMethodSource {
    IQueryable<TestReportModel> GetTestReport();
    QueryResult GetTestReportWithResult(QueryRequest request);
}
public class ExampleReportMethodSource : IExampleReportMethodSource {
    
    public IQueryable<TestReportModel> GetTestReport() {
        return new List<TestReportModel>().AsQueryable();
    }
    public QueryResult GetTestReportWithResult(QueryRequest request) {
        return new QueryResult();
    }
}
//The library will scan loaded assemblies for classes with the [TypeCacheInclude] attribute and add them to a cache. 
//This allows the library to return the correct type when executing a report method and deserializing the results.
//The MethodClass and MethodName are optional when the name of the class is the same as the name of the method.
//This can also be used to allow property information to be accessed on classes/types that do not have report methods associated, if needed.
[TypeCacheInclude(MethodClass = "ExampleReportMethodSource", MethodName = "GetTestReport")]
public class TestReportModel {
    public int Id { get; set; }
    public string Name { get; set; }
}

//in startup.cs or program.cs, register the report method source with the service collection


public void ConfigureServices(IServiceCollection services) {
    //register the class as a report method source, this will register the service as scoped so it can be injected where needed.

    services.AddReportSource<IExampleReportMethodSource, ExampleReportMethodSource>();

    //This is required to register the main report service which will be used to execute the reports built using this library. It should be registered after all report sources have been registered.
    //assemblyNamesToScan, if not provided the library will scan all loaded assemblies for report sources and types to add to the cache, but providing specific assemblies can improve startup performance by reducing the number of types that need to be scanned.
    services.AddTBARPTReportService(assemblyNamesToScan: ["MyProject.Assembly"]);
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider) {
    //This is required to use the report service, it should be registered after all report sources have been registered.
    app.UseTBARPTReportService();
}

//Use the report service to execute a report, this can be done in a controller or any other service where you have access to the report service through dependency injection.
public class ReportController : ControllerBase
{
    private readonly TBARPTReportService _tbarptReportService;

    public ReportController(TBARPTReportService reportService)
    {
        _tbarptReportService = reportService;
    }

    [HttpGet("execute-report")]
    public IActionResult ExecuteReport(QueryRequest queryRequest, string reportName)
    {
        var result = _tbarptReportService.GetReport(queryRequest, reportName);
        return Ok(result);
    }
}

AutoMapper Example usage:

//map individual object
DestinationType destination = AutoMapper.MapTo<DestinationType>(sourceObject);

//map individual object with property name mapping
Dictionary<string, string> propertyMap = new Dictionary<string, string> {
    { "DestinationPropertyName", "SourcePropertyName" }
};
DestinationType destination = AutoMapper.MapTo<DestinationType>(sourceObject, propertyMap);

//map list of objects
List<DestinationType> destinationList = AutoMapper.MapToList<DestinationType>(sourceObjects);

//map list of objects with property name mapping
Dictionary<string, string> propertyMap = new Dictionary<string, string> {
    { "DestinationPropertyName", "SourcePropertyName" }
};
List<DestinationType> destinationList = AutoMapper.MapToList<DestinationType>(sourceObjects, propertyMap);

DynamicJoinEngine Example usage:

// Example usage demonstrating case-insensitive keys
public class Program
{
    public static void Main()
    {
        // Create objects with differently cased property names
        var departments = new List<object>
        {
            new { DepartmentId = 1, Name = "Engineering" },
            new { DepartmentId = 2, Name = "Marketing" },
            new { departmentId = 3, Name = "Finance" }  // Note lowercase 'd' in departmentId
        };
        
        // Create ExpandoObjects with differently cased property names
        var employees = new List<object>();
        
        dynamic emp1 = new ExpandoObject();
        emp1.EmployeeId = 101;
        emp1.departmentId = 1;  // Note lowercase 'd' in departmentId
        emp1.Name = "John Doe";
        employees.Add(emp1);
        
        dynamic emp2 = new ExpandoObject();
        emp2.employeeId = 102;  // Note lowercase 'e' in employeeId
        emp2.DEPARTMENTID = 1;  // Note uppercase 'DEPARTMENTID'
        emp2.Name = "Jane Smith";
        employees.Add(emp2);
        
        dynamic emp3 = new ExpandoObject();
        emp3.EmployeeId = 103;
        emp3.DepartmentId = 2;
        emp3.Name = "Bob Johnson";
        employees.Add(emp3);
        
        // Example with composite keys of differently cased property names
        var projects = new List<object>();
        
        dynamic proj1 = new ExpandoObject();
        proj1.ProjectID = "P1";  // Note uppercase 'ID'
        proj1.DepartmentId = 1;
        proj1.ProjectName = "Website Redesign";
        projects.Add(proj1);
        
        dynamic proj2 = new ExpandoObject();
        proj2.projectId = "P2";  // Note lowercase 'projectId'
        proj2.DEPARTMENTID = 1;  // Note uppercase 'DEPARTMENTID'
        proj2.ProjectName = "Mobile App";
        projects.Add(proj2);
        
        // Initialize the dynamic join engine with case-insensitive keys (default)
        var joinEngine = new DynamicJoinFramework.DynamicJoinEngine()
            .AddTable("employees", employees)
            .AddTable("departments", departments)
            .AddJoin("employees", "departments", "departmentId", "DepartmentId", 
                    DynamicJoinFramework.JoinType.Left);
        
        var results = joinEngine.Execute();
        
        Console.WriteLine("Case-insensitive join results:");
        foreach (var item in results)
        {
            Console.WriteLine("---");
            if (item is IDictionary<string, object> expandoItem)
            {
                foreach (var kvp in expandoItem)
                {
                    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
                }
            }
        }
        
        // Composite key join with case-insensitive keys
        var compositeJoinEngine = new DynamicJoinFramework.DynamicJoinEngine()
            .AddTable("employees", employees)
            .AddTable("projects", projects)
            .AddJoin("employees", "projects", "departmentId", "DEPARTMENTID", 
                    DynamicJoinFramework.JoinType.Inner);
        
        var compositeResults = compositeJoinEngine.Execute();
        
        Console.WriteLine("\nComposite key case-insensitive join results:");
        foreach (var item in compositeResults)
        {
            Console.WriteLine("---");
            if (item is IDictionary<string, object> expandoItem)
            {
                foreach (var kvp in expandoItem)
                {
                    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
                }
            }
        }
        
        // Optional: Create a case-sensitive engine for comparison
        var caseSensitiveEngine = new DynamicJoinFramework.DynamicJoinEngine(caseInsensitiveKeys: false)
            .AddTable("employees", employees)
            .AddTable("departments", departments)
            .AddJoin("employees", "departments", "departmentId", "DepartmentId", 
                    DynamicJoinFramework.JoinType.Left);
        
        var sensitiveResults = caseSensitiveEngine.Execute();
        
        Console.WriteLine("\nCase-sensitive join results (for comparison):");
        Console.WriteLine($"Number of results: {sensitiveResults.Count()}"); // Should be fewer matches
    }
}
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.7 128 4/27/2026
1.5.6 118 4/21/2026
1.5.5 139 3/8/2026
1.5.4 113 3/6/2026
1.5.3 130 3/5/2026
1.5.2 113 3/5/2026
1.5.1 133 3/4/2026
Loading failed

Initial release.