### Install NeinLinq Packages Source: https://github.com/axelheer/nein-linq/blob/main/README.md Commands to install the various NeinLinq flavors via NuGet. ```powershell PM> Install-Package NeinLinq ``` ```powershell PM> Install-Package NeinLinq.EntityFramework ``` ```powershell PM> Install-Package NeinLinq.EntityFrameworkCore ``` -------------------------------- ### Install NeinLinq Packages Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/README.md Install the base NeinLinq package or specific packages for Entity Framework 6 or Entity Framework Core support. ```powershell Install-Package NeinLinq # Base package Install-Package NeinLinq.EntityFramework # EF6 support Install-Package NeinLinq.EntityFrameworkCore # EFCore support ``` -------------------------------- ### Install NeinLinq Base Package Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Installs the core NeinLinq functionality for in-memory LINQ to Objects queries. Use this for custom LINQ providers or non-database scenarios. ```powershell PM> Install-Package NeinLinq ``` -------------------------------- ### Install NeinLinq Entity Framework Core Package Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Installs the NeinLinq package for native Entity Framework Core support, featuring global configuration options. Method naming follows the base package conventions. ```powershell PM> Install-Package NeinLinq.EntityFrameworkCore ``` -------------------------------- ### Install NeinLinq Entity Framework 6 Package Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Installs the NeinLinq package optimized for Entity Framework 6, providing async-compatible query wrappers. Note the specific method naming conventions like ToDbInjectable(). ```powershell PM> Install-Package NeinLinq.EntityFramework ``` -------------------------------- ### Basic Lambda Injection Example Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Demonstrates how to mark a method for injection and provide its lambda expression. Use this pattern for simple, static extension methods. ```csharp // 1. Mark method as injectable [InjectLambda] public static string TruncateText(this string value, int length) { throw new NotImplementedException(); } // 2. Provide matching expression public static Expression> TruncateText() { return (v, l) => v != null && v.Length > l ? v.Substring(0, l) : v; } // 3. Use with ToInjectable() var query = data .ToInjectable() .Select(x => new { Name = x.Name.TruncateText(10) }); ``` -------------------------------- ### Unsupported LINQ Method Example Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/getting-started.md Demonstrates a common LINQ to Entities error when using unsupported methods. ```csharp from c in db.Courses select new { c.Id, Title = c.Title.LimitText(20) } ``` -------------------------------- ### Date Functions Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Shows examples of defining injectable date-related functions, such as `StartOfMonth`, to be used within LINQ queries. ```APIDOC ## Date Functions ```csharp [InjectLambda] public static DateTime StartOfMonth(this DateTime date) { throw new NotImplementedException(); } public static Expression> StartOfMonth() { return d => new DateTime(d.Year, d.Month, 1); } ``` ``` -------------------------------- ### Entity Framework Core Usage with NeinLinq Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Example demonstrating the usage of NeinLinq with Entity Framework Core, using methods like ToInjectable() for asynchronous database queries. ```csharp using NeinLinq; using NeinLinq.EntityFrameworkCore; var results = await _context.Courses .ToInjectable() .Where(c => c.IsActive) .ToListAsync(); ``` -------------------------------- ### Implement Injectable LINQ Query Methods Source: https://github.com/axelheer/nein-linq/blob/main/README.md Example of using ToInjectable with methods marked by InjectLambda to perform complex queries. ```csharp from d in data.ToInjectable() let e = d.RetrieveWhatever() where d.FulfillsSomeCriteria() select new { Id = d.Id, Value = d.DoTheFancy(e) } // ------------------------------------------------------------------- [InjectLambda] public static Whatever RetrieveWhatever(this Entity value) { throw new NotImplementedException(); } public static Expression> RetrieveWhatever() { return d => d.Whatevers.FirstOrDefault(e => ...); } [InjectLambda] public static bool FulfillsSomeCriteria(this Entity value) { throw new NotImplementedException(); } public static Expression> FulfillsSomeCriteria() { return d => ... } [InjectLambda] public static decimal DoTheFancy(this Entity value, Whatever other) { throw new NotImplementedException(); } public static Expression> DoTheFancy() { return (d, e) => ... } ``` -------------------------------- ### Entity Framework 6 Usage with NeinLinq Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Example demonstrating the usage of NeinLinq with Entity Framework 6, utilizing methods like ToDbInjectable() and ToDbNullsafe() for database queries. ```csharp using NeinLinq; using NeinLinq.EntityFramework; using (var db = new MyDbContext()) { var results = db.Courses .ToDbInjectable() .ToDbNullsafe() .Where(c => c.IsActive) .ToList(); } ``` -------------------------------- ### Custom InjectLambdaAttributeProvider Example Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Provides an example of a custom attribute provider function. This function determines if a member is injectable based on its name and returns an InjectLambdaAttribute if it is, otherwise falling back to the default provider. ```csharp InjectLambdaAttribute.SetAttributeProvider(memberInfo => { // Treat all methods starting with "Sql" as injectable if (memberInfo.Name.StartsWith("Sql")) { return new InjectLambdaAttribute(typeof(SqlExpressions), memberInfo.Name + "Expr"); } // Fallback to standard reflection-based provider var oldProvider = InjectLambdaAttribute.Provider; return oldProvider(memberInfo); }); ``` -------------------------------- ### SelectorTranslation Example Usage Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/types.md Demonstrates how to use SelectorTranslation to translate a selector from one type to another, specifically translating a Course selector to work with an Academy context. ```csharp var selectCourse = (Expression>) (c => new CourseView { Id = c.Id, Name = c.Name }); var selectFromAcademy = selectCourse .Translate() .Source(a => a.Courses.FirstOrDefault()); ``` -------------------------------- ### Aggregating and Translating Multiple Predicates for Dynamic Queries Source: https://github.com/axelheer/nein-linq/blob/main/README.md This example demonstrates a comprehensive approach to building a final query predicate by aggregating multiple predicates for different entities (Academy, Course, Lecture) and then translating them to be compatible with the target entity (`Course`). It avoids using `Invoke`, enhancing compatibility with LINQ providers like Entity Framework. ```csharp IEnumerable>> predicatesForAcademy = ... IEnumerable>> predicatesForCourse = ... IEnumerable>> predicatesForLecture = ... var singlePredicateForAcademy = predicatesForAcademy.Aggregate((p, q) => p.And(q)); var singlePredicateForCourse = predicatesForCourse.Aggregate((p, q) => p.And(q)); var singlePredicateForLecture = predicatesForLecture.Aggregate((p, q) => p.And(q)); var academyPredicateForCourse = singlePredicateForAcademy.Translate() .To(c => c.Academy); var coursePredicateForCourse = singlePredicateForCourse; // the hard one ^^ var lecturePredicateForCourse = singlePredicateForLecture.Translate() .To((c, p) => c.Lectures.Any(p)); var finalPredicate = academyPredicateForCourse.And(coursePredicateForCourse) .And(lecturePredicateForCourse); db.Courses.Where(finalPredicate)... ``` -------------------------------- ### Example: Using ToInjectable for Rewritten Query Enumeration Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Demonstrates how to use the ToInjectable extension method to create a rewritten query and then enumerate its results. The actual query rewriting occurs during this enumeration phase. ```csharp var rewritten = query.ToInjectable(); // Rewriting happens here during enumeration foreach (var item in rewritten) { // Process items } ``` -------------------------------- ### DynamicCompare Enum Example Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/dynamic-query.md Demonstrates how to use the DynamicCompare enum to define a comparison operation and apply it to filter data. This is useful for dynamically constructing query conditions. ```csharp var comparer = DynamicCompare.GreaterThan; var results = data.Where(x => x.Credits > 3); ``` -------------------------------- ### Entity Framework Core Async Query Injection Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Perform asynchronous queries with Entity Framework Core seamlessly using Nein.Linq. This example demonstrates standard async query execution and async enumeration. ```csharp // Works seamlessly var results = await _context.Courses .ToInjectable() .Where(c => c.IsActive) .ToListAsync(); ``` ```csharp // Async enumeration await foreach (var course in _context.Courses .ToInjectable() .Where(c => c.IsActive)) { await ProcessAsync(course); } ``` -------------------------------- ### Global EFCore Configuration for Lambda Injection Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/README.md Shows how to globally configure Nein LINQ's lambda injection for Entity Framework Core during DbContext setup. This allows custom methods to be used directly in queries without explicit calls to .ToInjectable(). ```csharp // Startup services.AddDbContext(options => options .UseSqlServer(connectionString) .WithLambdaInjection(typeof(StringHelpers))) // Global configuration // Queries automatically have injection var results = _context.Courses .Select(c => new { Title = c.Title.Truncate(20) }) .ToListAsync(); ``` -------------------------------- ### Math/Numeric Functions Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Provides examples of defining injectable math functions, such as `Round`, which can be used within LINQ queries after enabling injection. ```APIDOC ## Math/Numeric Functions ```csharp [InjectLambda] public static decimal Round(this decimal value, int decimals) { throw new NotImplementedException(); } public static Expression> Round() { return (v, d) => Math.Round(v, d); } ``` ``` -------------------------------- ### Translate Selector Expression Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/selector-translator.md Starts the translation process for a given selector expression. This is the entry point for translating a selector to be used with other entity types. ```csharp var selectAcademy = (Expression>) (a => new AcademyView { Id = a.Id, Name = a.Name }); var translation = selectAcademy.Translate(); // Now translate to SpecialAcademy var selectSpecial = translation.To(); ``` -------------------------------- ### Register Custom InjectLambdaAttribute Provider Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/types.md Example of registering a custom provider function for InjectLambdaAttribute. This allows for dynamic determination of lambda injection based on method names, such as prefixing with 'Sql'. ```csharp InjectLambdaAttribute.SetAttributeProvider(memberInfo => { if (memberInfo.Name.StartsWith("Sql")) { return new InjectLambdaAttribute(typeof(SqlExpressions)); } return InjectLambdaAttribute.Provider(memberInfo); }); ``` -------------------------------- ### RewriteQueryable IQueryProvider Property Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Gets the query provider. This implementation returns the RewriteQueryProvider, ensuring that subsequent query operations are also subject to rewriting. ```csharp IQueryProvider IQueryable.Provider { get; } ``` -------------------------------- ### Create Typed Predicate with Dynamic Comparison Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/types.md Example of creating a typed predicate for dynamic query filtering using the DynamicCompare enumeration. This is useful for filtering queryables based on dynamic criteria. ```csharp var result = DynamicQuery.CreatePredicate( "Credits", DynamicCompare.GreaterThanOrEqual, "3" ); ``` -------------------------------- ### Injectable Date Function: Start of Month Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Defines an injectable lambda function to get the first day of the month for a given date. Use the `[InjectLambda]` attribute for seamless query usage. ```csharp [InjectLambda] public static DateTime StartOfMonth(this DateTime date) { throw new NotImplementedException(); } ``` ```csharp public static Expression> StartOfMonth() { return d => new DateTime(d.Year, d.Month, 1); } ``` -------------------------------- ### SelectorTranslator.Translate Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/selector-translator.md Starts the translation of a lambda expression selector. This method is used as a starting point for translating a selector to be compatible with different entity types. ```APIDOC ## Translate ### Description Starts translation of a selector for use with other entity types. ### Method `public static SelectorTranslation Translate(this Expression> selector)` ### Parameters #### Path Parameters - **selector** (`Expression>`) - Required - The selector to translate ### Returns `SelectorTranslation` - Translation builder for fluent chaining ### Example ```csharp var selectAcademy = (Expression>) (a => new AcademyView { Id = a.Id, Name = a.Name }); var translation = selectAcademy.Translate(); // Now translate to SpecialAcademy var selectSpecial = translation.To(); ``` ``` -------------------------------- ### Basic Translation with Source Path Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/selector-translator.md Demonstrates basic translation by defining a base selector and then translating it to access data through a specific source path, such as nested collections. ```csharp // Define a base selector var selectCourse = (Expression>) (c => new CourseView { Id = c.Id, Title = c.Title, Credits = c.Credits }); // Translate to access through Academy var fromAcademy = selectCourse .Translate() .Source(a => a.Courses.FirstOrDefault()); // Use it var result = db.Academies.Select(fromAcademy); ``` -------------------------------- ### InjectLambdaAttribute.Provider Property Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Gets or sets the current attribute provider. This property defaults to a reflection-based lookup mechanism. ```APIDOC ## Static Methods ### Provider ```csharp public static InjectLambdaAttributeProvider Provider { get; private set; } ``` The current attribute provider. Defaults to reflection-based lookup using `GetCustomAttribute`. **Example:** ```csharp var provider = InjectLambdaAttribute.Provider; var attr = provider(typeof(MyClass).GetMethod("MyMethod")); ``` ``` -------------------------------- ### Abstract SQL Functions with Lambda Injection Source: https://github.com/axelheer/nein-linq/blob/main/README.md Demonstrates abstracting provider-specific functions like SQL LIKE using lambda injection. ```csharp [InjectLambda] public static bool Like(this string value, string likePattern) { throw new NotImplementedException(); } public static Expression> Like() { return (v, p) => SqlFunctions.PatIndex(p, v) > 0; } // ------------------------------------------------------------------- from d in data.ToInjectable() where d.Name.Like("%na_f%") select ... ``` -------------------------------- ### RewriteQueryable Expression Property Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Gets the expression tree of the underlying query. This property is part of the IQueryable interface implementation. ```csharp public Expression Expression { get; } ``` -------------------------------- ### Project File Structure Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/INDEX.md Overview of the Nein.Linq project's directory and file organization. Useful for understanding where different types of documentation and code reside. ```text output/ ├── README.md # Main overview ├── INDEX.md # This file ├── getting-started.md # Quick introduction ├── configuration.md # Setup and options ├── types.md # Type reference ├── advanced-patterns.md # Complex patterns └── api-reference/ ├── cached-expression.md # CachedExpression ├── lambda-injection.md # [InjectLambda] attribute ├── injectable-query.md # Lambda injection guide ├── predicate-translator.md # Predicate composition/translation ├── selector-translator.md # Selector composition/translation ├── dynamic-query.md # Dynamic filtering/sorting ├── query-builders.md # Extension methods └── rewrite-queryable.md # RewriteQueryable ``` -------------------------------- ### General Method Signature for Injectable Queries Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Illustrates the general signature requirements for both the injectable method (using [InjectLambda]) and its corresponding expression method, emphasizing compatible parameter and return types. ```csharp // Injectable method: TResult MethodName(T1 arg1, T2 arg2, ...) [InjectLambda] public static TResult MethodName(this T0 target, T1 arg1, T2 arg2) { throw new NotImplementedException(); } // Expression method: Expression> MethodName() public static Expression> MethodName() { return (t, a1, a2) => /* expression */; } ``` -------------------------------- ### Multi-Level Predicate Translation Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/advanced-patterns.md Translate a predicate across multiple relationship levels, starting from a grandchild entity (Lecture) up to a grandparent entity (Academy). ```csharp // Start with Lecture predicate var interestingLectures = (Expression>) (l => l.IsRequired && l.Duration > 60); // Translate to Course var coursesWithInterestingLectures = interestingLectures .Translate() .To((c, p) => c.Lectures.Any(p)); // Translate to Academy var academiesWithInterestingCourses = coursesWithInterestingLectures .Translate() .To((a, p) => a.Courses.Any(p)); var results = db.Academies .Where(academiesWithInterestingCourses) .ToList(); ``` -------------------------------- ### PredicateTranslator.Translate Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/predicate-translator.md Starts the translation of a predicate for use with other entity types. This method returns a builder that allows for fluent chaining of translation operations. ```APIDOC ## Translate ### Description Starts translation of a predicate for use with other entity types. ### Method `public static PredicateTranslation Translate(this Expression> predicate)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **predicate** (`Expression>`) - Required - The predicate to translate ### Returns `PredicateTranslation` — Translation builder for fluent chaining ### Example ```csharp Expression> academyPredicate = a => a.Name.Contains("Tech"); var translation = academyPredicate.Translate(); // Now translate to Course through the academy relationship var coursePredicate = translation.To(c => c.Academy); ``` ``` -------------------------------- ### Instantiating RewriteQueryable Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Shows how RewriteQueryable is created indirectly via extension methods like ToInjectable(). The internal instantiation is also noted. ```csharp // Created indirectly through extension methods var rewritten = dbContext.Courses.ToInjectable(); // Internally: new RewriteQueryable(dbContext.Courses, provider) ``` -------------------------------- ### Get Default Attribute Provider Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Retrieves the current default attribute provider used by NeinLinq for finding the `[InjectLambda]` attribute via reflection. ```csharp var provider = InjectLambdaAttribute.Provider; // Current provider var attr = provider(methodInfo); // Returns attribute or null ``` -------------------------------- ### Combining Nein.Linq Features Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Demonstrates chaining multiple Nein.Linq extensions like ToInjectable, ToNullsafe, and dynamic sorting within a single query. ```csharp var results = db.Courses .ToInjectable(typeof(StringHelpers)) // Enable lambda injection .ToNullsafe() // Add null-safety .Where(c => c.IsActive) .Select(c => new { c.Id, Title = c.Title.Truncate(25), // Injected AcademyName = c.Academy.Name // Safe if Academy is null }) .OrderBy("Name") // Dynamic sorting .ToList(); ``` -------------------------------- ### RewriteQueryable.DebugString Property Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Gets a debug representation of the underlying query expression tree. This property is useful for troubleshooting and inspecting the structure of rewritten queries. ```APIDOC ## RewriteQueryable.DebugString Property ### Description Gets a debug representation of the underlying query expression tree. Useful for troubleshooting and inspecting query structure. ### Property - **DebugString** (string?) - String representation of the query ### Example ```csharp var rewritten = dbContext.Courses.ToInjectable(); var debug = rewritten.DebugString; // Output shows the internal LINQ expression tree ``` ``` -------------------------------- ### Repository Pattern with NeinLinq Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/advanced-patterns.md Implement a generic repository with methods for injectable and nullsafe queries using NeinLinq. This pattern centralizes data access logic. ```csharp public interface IRepository where T : class { IQueryable GetInjectableQuery(); IQueryable GetNullsafeQuery(); } public class Repository : IRepository where T : class { private readonly DbContext context; public Repository(DbContext context) { this.context = context; } public IQueryable GetInjectableQuery() { return context.Set().ToInjectable(typeof(CommonHelpers)); } public IQueryable GetNullsafeQuery() { return context.Set().ToNullsafe(); } } // Usage in service public class CourseService { private readonly IRepository repository; public async Task> SearchAsync(string keyword) { return await repository .GetInjectableQuery() .Where(c => c.Name.Contains(keyword)) .Select(c => new CourseDTO { Id = c.Id, Title = c.Title.Truncate(50) }) .ToListAsync(); } } ``` -------------------------------- ### Inject Instance Methods and Interfaces Source: https://github.com/axelheer/nein-linq/blob/main/README.md Inject instance methods or use interfaces to abstract expression logic. ```csharp public class ParameterizedFunctions { private readonly int narf; public ParameterizedFunctions(int narf) { this.narf = narf; } [InjectLambda("FooExpr")] public string Foo() { ... } public Expression> FooExpr() { ... // use the narf! } } // ------------------------------------------------------------------- public interface IFunctions { [InjectLambda] string Foo(Entity value); // use abstraction for queries } public class Functions : IFunctions { [InjectLambda] public string Foo(Entity value) { ... } public Expression> Foo() { ... } } ``` -------------------------------- ### InjectLambdaAttribute Constructors Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Demonstrates the different constructors for the InjectLambdaAttribute, each allowing for specific configurations of target type and method name for lambda expression injection. ```APIDOC ## InjectLambdaAttribute() ### Description Marks a method as injectable using default conventions: expression method has the same name in the same type. ### Example: ```csharp [InjectLambda] public static string LimitText(this string value, int maxLength) { throw new NotImplementedException(); } public static Expression> LimitText() { return (v, l) => v != null && v.Length > l ? v.Substring(0, l) : v; } ``` ## InjectLambdaAttribute(Type) ### Description Marks a method as injectable with the expression in a different type. ### Parameters #### Path Parameters - **target** (Type) - Required - Type containing the expression method ### Throws: - `ArgumentNullException` — if `target` is null ### Example: ```csharp [InjectLambda(typeof(StringExpressions))] public static string Sanitize(this string value) { throw new NotImplementedException(); } public static class StringExpressions { public static Expression> Sanitize() { return s => s.Replace("<", "<").Replace(">", ">"); } } ``` ## InjectLambdaAttribute(Type, string) ### Description Marks a method as injectable with a specific target type and expression method name. ### Parameters #### Path Parameters - **target** (Type) - Required - Type containing the expression method - **method** (string) - Required - Name of the expression method in the target type ### Throws: - `ArgumentNullException` — if `target` or `method` is null or empty ### Example: ```csharp [InjectLambda(typeof(SqlExpressions), nameof(SqlExpressions.LikeExpr))] public static bool Like(this string value, string pattern) { throw new NotImplementedException(); } public static class SqlExpressions { public static Expression> LikeExpr() { return (v, p) => v != null && EF.Functions.Like(v, p); } } ``` ## InjectLambdaAttribute(string) ### Description Marks a method as injectable with a custom expression method name in the same type. ### Parameters #### Path Parameters - **method** (string) - Required - Name of the expression method ### Throws: - `ArgumentNullException` — if `method` is null or empty ### Example: ```csharp [InjectLambda(nameof(ComputeVelocityExpr))] public double ComputeVelocity(double distance, double time) { throw new NotImplementedException(); } public static Expression> ComputeVelocityExpr() { return (d, t) => t != 0 ? d / t : 0; } ``` ``` -------------------------------- ### Global Greenlist Configuration for EF Core Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Set up a global greenlist for all queries within a DbContext using Entity Framework Core. This ensures that methods from the specified types are always available for injection. ```csharp services.AddDbContext(options => options .UseSqlServer(connectionString) .WithLambdaInjection( typeof(StringExtensions), typeof(DateExtensions) ) ); ``` -------------------------------- ### Get Current Attribute Provider Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Retrieves the current attribute provider function. This can be used to store the current provider before setting a new one, or to directly invoke the provider. ```csharp var provider = InjectLambdaAttribute.Provider; var attr = provider(typeof(MyClass).GetMethod("MyMethod")); ``` -------------------------------- ### Dynamic Ordering with OrderBy Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/dynamic-query.md Dynamically sort query results by a specified property path. Set the 'descending' parameter to true for reverse order. This method is the entry point for ordering. ```csharp var results = db.Courses .OrderBy("Name") // Ascending .ThenBy("Credits", descending: true) // Descending .ToList(); ``` -------------------------------- ### Custom Attribute Provider for Injectable Methods Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Implement a custom attribute provider to define injectable methods without using the [InjectLambda] attribute, for example, by following naming conventions. ```csharp InjectLambdaAttribute.SetAttributeProvider(memberInfo => { // Check for naming convention instead of attribute if (memberInfo.Name.EndsWith("_Injected")) { return new InjectLambdaAttribute(typeof(ExternalExpressions)); } // Fall back to standard attribute lookup return Attribute.GetCustomAttribute(memberInfo, typeof(InjectLambdaAttribute)) as InjectLambdaAttribute; }); // Now these work without [InjectLambda]: public static string Format_Injected(this string value, string format) { ... } ``` -------------------------------- ### Enable Global Lambda Injection for EF Core Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/getting-started.md Configure Entity Framework Core to globally enable lambda injection during startup. This allows custom extension methods like Truncate to be used seamlessly in queries. ```csharp // Startup services.AddDbContext(options => options .UseSqlServer(connectionString) .WithLambdaInjection() // Enable globally ); // Queries automatically have injection enabled var results = _context.Courses .Select(c => new { Title = c.Title.Truncate(20) }) .ToListAsync(); ``` -------------------------------- ### Use Parameterized Expressions with Instance Methods Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Instance methods can capture constructor parameters, enabling parameterized expressions. This is useful for creating queries with context-specific logic, such as filtering by a specific company ID. ```csharp using System.Linq.Expressions; public class Company { public int CompanyId { get; set; } } public class CompanySpecificFunctions { private readonly int companyId; public CompanySpecificFunctions(int companyId) { this.companyId = companyId; } [InjectLambda(nameof(FilteredExpr))] public bool IsCompanyRecord(Company record) { throw new NotImplementedException(); } public Expression> FilteredExpr() { // Closure captures companyId return c => c.CompanyId == companyId; } } // Example usage: // var functions = new CompanySpecificFunctions(42); // var query = dbContext.Companies // .ToInjectable() // .Where(c => functions.IsCompanyRecord(c)); ``` -------------------------------- ### Filter Data from User Input Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/getting-started.md Dynamically filter and sort queryable data based on user input parameters. This example demonstrates using string methods for filtering and dynamic sorting. ```csharp public IQueryable GetCourses( string? nameFilter, string? sortField, bool sortDescending = false) { var query = _context.Courses; if (!string.IsNullOrEmpty(nameFilter)) { query = query.Where("Name", "Contains", nameFilter); } if (!string.IsNullOrEmpty(sortField)) { query = query.OrderBy(sortField, sortDescending); } return query; } ``` -------------------------------- ### Provider Compatibility with NeinLinq Features Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Test your specific LINQ provider's compatibility with NeinLinq features. Some features, like ToSubstitution, may not work with all providers (e.g., LINQ to XML). ```csharp // Works with most providers .ToInjectable() .ToNullsafe() .Where(c => c.IsActive) // May not work with some providers (e.g., LINQ to XML) .ToSubstitution(typeof(A), typeof(B)) ``` -------------------------------- ### Define Custom String Extension Function Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/getting-started.md Define a custom string extension method with the [InjectLambda] attribute to make it usable within LINQ queries. This example shows a Truncate function. ```csharp public static class StringExtensions { [InjectLambda] public static string Truncate(this string value, int maxLen) { return value?.Length > maxLen ? value.Substring(0, maxLen) : value; } public static Expression> Truncate() { return (v, l) => v != null && v.Length > l ? v.Substring(0, l) : v; } } ``` ```csharp // Usage var courses = db.Courses .ToInjectable() .Select(c => new { c.Id, Title = c.Title.Truncate(20) }) .ToList(); ``` -------------------------------- ### Chaining Multiple Query Rewriters Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Illustrates how to chain multiple query rewriters, where each subsequent rewriter creates its own RewriteQueryProvider that wraps the previous one. ```csharp // Equivalent to: var step1 = source.Rewrite(new InjectableQueryRewriter()); var step2 = step1.Rewrite(new NullsafeQueryRewriter()); var step3 = step2.Rewrite(new SubstitutionQueryRewriter(...)); // Each has its own RewriteQueryProvider wrapping the previous ``` -------------------------------- ### Substitute Production Methods for Testing Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/advanced-patterns.md Replace production methods with test implementations during testing. This allows for isolated testing of logic that depends on external or complex production methods. ```csharp public static class ProductionFunctions { public static int Distance(decimal lat1, decimal lon1, decimal lat2, decimal lon2) { // Sophisticated distance calculation throw new NotImplementedException(); } } public static class TestFunctions { public static int Distance(decimal lat1, decimal lon1, decimal lat2, decimal lon2) { // Simple test implementation return 10; } } // Test [Test] public void TestNearbyStores() { var results = db.Stores .ToSubstitution(typeof(ProductionFunctions), typeof(TestFunctions)) .Where(s => s.Distance(40.7128m, -74.0060m, 40.7200m, -74.0100m) < 5) .ToList(); Assert.AreEqual(expectedCount, results.Count); } ``` -------------------------------- ### Translate Predicate for Related Types Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/predicate-translator.md Starts the translation process for a predicate, enabling it to be used with related entity types. Use this when you need to adapt a predicate defined for one type to another related type (e.g., through inheritance or composition). ```csharp Expression> academyPredicate = a => a.Name.Contains("Tech"); var translation = academyPredicate.Translate(); // Now translate to Course through the academy relationship var coursePredicate = translation.To(c => c.Academy); ``` -------------------------------- ### Building Dynamic Queries from User Input Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/dynamic-query.md Construct dynamic queries programmatically based on string inputs for property names, comparison methods, and values. This enables flexible filtering based on user-provided criteria. ```csharp public IQueryable FilterCourses( string? propertyName, string? compareMethod, string? value) { var query = _db.Courses; if (!string.IsNullOrEmpty(propertyName)) { query = query.Where(propertyName, compareMethod ?? "Equals", value); } return query; } ``` -------------------------------- ### RewriteQueryable Constructor Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Initializes a new instance of the RewriteQueryable class, wrapping an existing query with a specific provider. ```APIDOC ### Constructor ```csharp protected RewriteQueryable(IQueryable query, RewriteQueryProvider provider) ``` Creates a new rewritten query proxy. | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | query | `IQueryable` | Yes | — | The underlying query to wrap | | provider | `RewriteQueryProvider` | Yes | — | The provider with the rewriter | **Throws:** - `ArgumentNullException` — if `query` or `provider` is null **Note:** This is a protected constructor; use derived class `RewriteQueryable` or extension methods like `ToInjectable()`. ``` -------------------------------- ### Per-Query Greenlist Configuration Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Enable injection for specific helper types within a single query without needing [InjectLambda] attributes on their methods. This is useful for ad-hoc injection scenarios. ```csharp // Enable injection for MyHelpers class without [InjectLambda] attributes var results = db.Courses .ToInjectable(typeof(MyHelpers)) .Select(c => new { c.Id, Cleaned = c.Name.Sanitize() }) .ToList(); ``` -------------------------------- ### Lookup/Translation Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Demonstrates how to implement injectable lookup or translation functions, like `StatusDescription`, which can map codes to descriptions within LINQ queries. ```APIDOC ## Lookup/Translation ```csharp [InjectLambda(typeof(LookupExpressions))] public static string StatusDescription(this string statusCode) { throw new NotImplementedException(); } public static Expression> StatusDescription() { // Use dictionary lookups in expression var statusMap = new Dictionary { ... }; return code => statusMap.ContainsKey(code) ? statusMap[code] : code; } ``` ``` -------------------------------- ### Combining with Other Features Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Demonstrates how to use `ToInjectable` to enable custom lambda injection within a LINQ query, combined with other features like null-safety, dynamic sorting, and projection. ```APIDOC ## Combining with Other Features ```csharp var results = db.Courses .ToInjectable(typeof(StringHelpers)) // Enable lambda injection .ToNullsafe() // Add null-safety .Where(c => c.IsActive) .Select(c => new { c.Id, Title = c.Title.Truncate(25), // Injected AcademyName = c.Academy.Name // Safe if Academy is null }) .OrderBy("Name") // Dynamic sorting .ToList(); ``` ``` -------------------------------- ### String Functions Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Illustrates how to create injectable string manipulation functions, like `GetWordCount`, for use in LINQ queries. ```APIDOC ## String Functions ```csharp [InjectLambda] public static int GetWordCount(this string value) { return value?.Split(' ').Length ?? 0; } public static Expression> GetWordCount() { return v => v.Split(' ').Length; } ``` ``` -------------------------------- ### Instance-Based Lambda Injection Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/advanced-patterns.md Use instance state in injectable expressions by capturing instance members, such as `tenantId`, within the injected lambda. This requires the `TenantAwareHelpers` class and the `InjectLambda` attribute. ```csharp public class TenantAwareHelpers { private readonly int tenantId; public TenantAwareHelpers(int tenantId) { this.tenantId = tenantId; } [InjectLambda(nameof(IsTenantOwnerExpr))] public bool IsTenantOwner(Entity entity) { return entity.TenantId == tenantId; } public Expression> IsTenantOwnerExpr() { // Closure captures tenantId return e => e.TenantId == tenantId; } } // Usage with DI var tenantHelpers = new TenantAwareHelpers(currentTenantId); var query = db.Entities .ToInjectable() .Where(e => tenantHelpers.IsTenantOwner(e)); ``` -------------------------------- ### Parameterized Lambda Injection Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Shows how to inject lambda expressions for instance methods, allowing access to instance state like 'maxLength'. This is useful for reusable functions with configurable behavior. ```csharp public class ParameterizedFunctions { private readonly int maxLength; public ParameterizedFunctions(int maxLength) { this.maxLength = maxLength; } [InjectLambda(nameof(LimitExpr))] public string Limit(string value) { return value != null && value.Length > maxLength ? value.Substring(0, maxLength) : value; } public Expression> LimitExpr() { return v => v != null && v.Length > maxLength ? v.Substring(0, maxLength) : v; } } ``` -------------------------------- ### Build Dynamic LINQ Queries (C#) Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/README.md Construct LINQ queries dynamically from user input using `DynamicQueryable`. This method allows specifying filters and ordering based on string representations of property names, comparison operations, and values, making it suitable for dynamic search and filtering scenarios. ```csharp // Hard to make type-safe var filterName = userInput.PropertyName; // "Name" var operation = userInput.Comparison; // "Contains" var value = userInput.Value; // "Math" ``` ```csharp var results = db.Courses .Where("Name", "Contains", "Math") .Where("Credits", DynamicCompare.GreaterThan, "3") .OrderBy("Name") .ThenBy("Credits", descending: true) .ToList(); ``` -------------------------------- ### Transparent Chaining with RewriteQueryable Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Demonstrates how RewriteQueryable integrates seamlessly into LINQ query chains, allowing extension methods to pass through to the underlying provider. ```csharp var query = source .ToInjectable() // Returns RewriteQueryable .Where(x => x.IsActive) // Extension method calls through Provider .Select(x => x.Name) // Continues through Provider .OrderBy(x => x); // Continues through Provider ``` -------------------------------- ### Set Custom Attribute Provider with Fallback Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/lambda-injection.md Demonstrates setting a new custom attribute provider while preserving the old one for fallback. This pattern is useful for extending existing injection logic. ```csharp var oldProvider = InjectLambdaAttribute.Provider; InjectLambdaAttribute.SetAttributeProvider(memberInfo => { // Custom logic here if (IsExternalLibraryMethod(memberInfo)) { return new InjectLambdaAttribute(typeof(ExternalExpressions), memberInfo.Name); } return oldProvider(memberInfo); }); ``` -------------------------------- ### Executing Rewritten Query with GetEnumerator Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Demonstrates how to execute a rewritten query and iterate over the results using a standard foreach loop. This utilizes the GetEnumerator method. ```csharp var rewritten = dbContext.Courses .ToInjectable() .Where(c => c.IsActive); foreach (var course in rewritten) { Console.WriteLine(course.Name); } ``` -------------------------------- ### Combine Multiple Nein LINQ Features Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/README.md Demonstrates combining multiple Nein LINQ features like lambda injection, null-safety, dynamic filtering, custom method usage, and dynamic sorting in a single query. Ensure custom helper methods are marked with [InjectLambda] or provided via configuration. ```csharp // Helper: Custom string function public static class StringHelpers { [InjectLambda] public static string Truncate(this string value, int length) { return value?.Length > length ? value.Substring(0, length) : value; } public static Expression> Truncate() { return (v, l) => v != null && v.Length > l ? v.Substring(0, l) : v; } } // Query combining multiple features var results = _context.Courses .ToInjectable() // Enable lambda injection .ToNullsafe() // Add null-safety .Where("Name", "Contains", userInput.SearchTerm) // Dynamic filter .Select(c => new CourseDTO { Id = c.Id, Title = c.Title.Truncate(20), // Custom function AcademyName = c.Academy?.Name, // Safe null access Active = c.IsActive }) .OrderBy("Title") // Dynamic sorting .ToListAsync(); ``` -------------------------------- ### Greenlist Entire Type for Injectable Methods Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Enable all methods in a type as injectable without marking each with `[InjectLambda]` by using the type as a greenlist. This is useful for utility classes where all methods are intended for query projection. ```csharp public class StringHelpers { // No attributes needed! public static string Truncate(this string value, int length) { throw new NotImplementedException(); } public static string Sanitize(this string value) { throw new NotImplementedException(); } } public static class StringHelpersExpressions { public static Expression> Truncate() { return (v, l) => v != null && v.Length > l ? v.Substring(0, l) : v; } public static Expression> Sanitize() { return v => v.Replace("<", "<").Replace(">", ">"); } } // Enable entire type as greenlist var results = db.Courses .ToInjectable(typeof(StringHelpers)) .Select(c => new { c.Id, Title = c.Title.Truncate(20) }) .ToList(); ``` -------------------------------- ### DynamicExpression Utilities Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/types.md Low-level utilities for building dynamic expressions. Register custom type converters as needed. ```csharp public static class DynamicExpression ``` -------------------------------- ### Implicit Conversion to CachedExpression Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/cached-expression.md Shows how an expression tree can be implicitly converted to a CachedExpression, simplifying the creation process. ```csharp Expression> expr = x => x * 2; CachedExpression> cached = expr; // Implicit conversion ``` -------------------------------- ### RewriteQueryable Constructor Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Protected constructor for creating a new rewritten query proxy. It requires the underlying query and the rewriter provider. Use derived classes or extension methods for instantiation. ```csharp protected RewriteQueryable(IQueryable query, RewriteQueryProvider provider) ``` -------------------------------- ### Translating Child Entity Predicates to Parent Entity Source: https://github.com/axelheer/nein-linq/blob/main/README.md Illustrates how to translate a predicate defined for a child entity (e.g., `Lecture`) to a predicate applicable to a parent entity (e.g., `Course`) using NeinLinq's `Translate()` and `To()` methods with a lambda for the relationship. This enables querying parent entities based on conditions in their related child entities. ```csharp Expression> p = l => ... db.Courses.Where(p.Translate() .To((c, q) => c.Lectures.Any(q)))... ``` -------------------------------- ### Substitute Provider-Specific Types in Queries (C#) Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/README.md Replace hard dependencies on provider-specific types, such as `SqlFunctions`, with alternative implementations using `.ToSubstitution(from, to)`. This is particularly useful for enabling unit testing by substituting production types with fake or mock implementations. ```csharp // Production: Use SqlFunctions var prod = db.Products .ToSubstitution(typeof(SqlFunctions), typeof(SqlFunctions)) .Where(p => SqlFunctions.PatIndex("%sale%", p.Name) > 0); // Testing: Use fake implementation var test = db.Products .ToSubstitution(typeof(SqlFunctions), typeof(FakeSqlFunctions)) .Where(p => SqlFunctions.PatIndex("%sale%", p.Name) > 0); ``` -------------------------------- ### Use Greenlist for Entire Namespace Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Apply lambda injection for all methods within a specified namespace using the ToInjectable extension method. This is an alternative to marking individual methods with [InjectLambda]. ```csharp // Option B: Use greenlist for entire namespace var results = query.ToInjectable(typeof(Helpers)); ``` -------------------------------- ### SelectorTranslation Constructor Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/selector-translator.md Initializes a new instance of the SelectorTranslation class with a given selector expression. ```APIDOC ## SelectorTranslation Constructor ### Description Creates a new selector translation builder. ### Parameters #### Parameters - **selector** (`Expression>`) - Required - The selector to translate ### Throws - `ArgumentNullException` - if `selector` is null ``` -------------------------------- ### Chaining Multiple Rewriters Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/rewrite-queryable.md Illustrates how multiple rewriters, such as ToInjectable(), ToNullsafe(), and ToSubstitution(), can be chained together. Rewriting occurs in order during enumeration. ```csharp var query = dbContext.Courses .ToInjectable() .ToNullsafe() .ToSubstitution( typeof(SqlFunctions), typeof(TestFunctions) ); ``` -------------------------------- ### SubstitutionQueryBuilder.ToSubstitution Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/types.md Substitutes method types within a query. ```APIDOC ## SubstitutionQueryBuilder.ToSubstitution ### Description Substitute method types. ### Method Signature `IQueryable ToSubstitution(IQueryable query, Type from, Type to)` ``` -------------------------------- ### Combining Selectors with Apply Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/selector-translator.md Shows how to merge two selectors into a single, combined selector. This is useful for building complex selection logic by composing smaller, reusable selector expressions. ```csharp var selectBase = (Expression>) (c => new CourseView { Id = c.Id, Title = c.Title }); var selectExtended = (Expression>) (c => new CourseView { Credits = c.Credits, IsActive = c.IsActive }); // Merge bindings var selectFull = selectBase.Apply(selectExtended); var result = db.Courses.Select(selectFull); ``` -------------------------------- ### Wrapping SQL Functions with Injectable Methods Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/api-reference/injectable-query.md Define SQL-specific helper methods that wrap EF.Functions to avoid direct dependencies. Use these methods in your queries after marking them with [InjectLambda]. ```csharp // SQL-specific helper public static class SqlHelpers { [InjectLambda(typeof(SqlHelperExpressions))] public static bool Like(this string value, string pattern) { throw new NotImplementedException(); } } // Expressions using EF.Functions public static class SqlHelperExpressions { public static Expression> Like() { return (v, p) => EF.Functions.Like(v, p); } } // Use without direct EF.Functions reference var results = db.Products .ToInjectable() .Where(p => p.Name.Like("%electronics%")) .ToList(); ``` -------------------------------- ### Checking Generated SQL with NeinLinq Source: https://github.com/axelheer/nein-linq/blob/main/_autodocs/configuration.md Always verify the generated SQL to ensure efficient translation of expressions. Use ToQueryString() to inspect the SQL generated by your NeinLinq query. ```csharp var query = _context.Courses .ToInjectable() .Where(c => c.Name.Truncate(20) != ""); // Check generated SQL var sql = query.ToQueryString(); ```