TBARPT.Library
1.5.7
dotnet add package TBARPT.Library --version 1.5.7
NuGet\Install-Package TBARPT.Library -Version 1.5.7
<PackageReference Include="TBARPT.Library" Version="1.5.7" />
<PackageVersion Include="TBARPT.Library" Version="1.5.7" />
<PackageReference Include="TBARPT.Library" />
paket add TBARPT.Library --version 1.5.7
#r "nuget: TBARPT.Library, 1.5.7"
#:package TBARPT.Library@1.5.7
#addin nuget:?package=TBARPT.Library&version=1.5.7
#tool nuget:?package=TBARPT.Library&version=1.5.7
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
- Add this package and dependencies
- 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 | Versions 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. |
-
net8.0
- Microsoft.AspNetCore.Http.Abstractions (>= 2.2.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.0)
- Newtonsoft.Json (>= 13.0.3)
- System.Linq.Dynamic.Core (>= 1.7.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release.