### Entity Framework Core Repository Implementation with C# Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Demonstrates the implementation of a generic repository pattern using Entity Framework Core in C#. It includes defining an entity, a repository class inheriting from a base repository, and examples of common repository operations like insert, retrieve, update, delete, and custom queries. ```csharp using PPWCode.Vernacular.Persistence.V; using PPWCode.Vernacular.EntityFrameworkCore.I; using Microsoft.EntityFrameworkCore; // Define entity public class Order : PersistentObject { public string CustomerName { get; set; } = string.Empty; public DateTime OrderDate { get; set; } public decimal TotalAmount { get; set; } } // Define repository public class OrderRepository : Repository { public OrderRepository(PpwDbContext dbContext) : base(dbContext) { } // Custom query method using protected FindAsync public async Task> FindByCustomerAsync( string customerName, CancellationToken ct = default) { return await FindAsync( query => query .Where(o => o.CustomerName == customerName) .OrderByDescending(o => o.OrderDate), cancellationToken: ct); } // Paged query public async Task> FindRecentOrdersPagedAsync( int pageIndex, int pageSize, CancellationToken ct = default) { return await FindPagedAsync( query => query.OrderByDescending(o => o.OrderDate), pageIndex, pageSize, ct); } } // Usage public async Task RepositoryUsageExample(OrderRepository repo) { // Insert var order = new Order { CustomerName = "Acme Corp", OrderDate = DateTime.UtcNow, TotalAmount = 1500.00m }; await repo.InsertAsync(order); await repo.FlushAsync(); // Retrieve Order? retrieved = await repo.GetByIdAsync(order.Id); List allOrders = await repo.FindAllAsync(); // Update retrieved!.TotalAmount = 1750.00m; await repo.UpdateAsync(retrieved); await repo.FlushAsync(); // Custom queries var customerOrders = await repo.FindByCustomerAsync("Acme Corp"); var pagedOrders = await repo.FindRecentOrdersPagedAsync(1, 10); Console.WriteLine($"Page {pagedOrders.PageIndex} of {pagedOrders.TotalPages}"); Console.WriteLine($"Total items: {pagedOrders.TotalItemCount}"); // Delete await repo.DeleteAsync(retrieved); await repo.FlushAsync(); } ``` -------------------------------- ### Initialize and Update Git Submodule Source: https://github.com/peopleware/net-ppwcode-vnext/blob/main/README.md Instructions for users who have pulled changes containing a submodule update. This includes initializing the submodule and updating it to the registered version (tag). ```shell # first go to the root of your code base # then pull the changes from origin git pull origin --ff-only # local code base now contains submodule configuration # however: submodule must still be initialized # # create the submodule folder and clone the repo git submodule init # switch to the registered version of the submodule code # note: this switches to the tag preview/20250309b git submodule update ``` -------------------------------- ### Add PPWCode.vNext Git Submodule Source: https://github.com/peopleware/net-ppwcode-vnext/blob/main/README.md Commands to add the PPWCode.vNext Git repository as a submodule to your project. This involves navigating to your project's root, adding the submodule, checking out a specific tag for stability, committing the submodule configuration, and pushing the changes. ```shell # first go to the root of your code base # then add the submodule in the folder `ppwcode-vnext` # # add `net-ppwcode-vnext` repo as submodule in folder `ppwcode-vnext` git submodule add https://github.com/peopleware/net-ppwcode-vnext.git ppwcode-vnext # prev cmd uses the default branch of the `ppwcode-vnext` repo # it is recommended to fix the submodule to a specific tag # this can be done in the folder of the submodule, it is a git repo cd ppwcode-vnext git checkout preview/20250309b # submodule is correctly configured now # commit the submodule configuration cd .. git commit -m "Add submodule for ppwcode-vnext on preview/20250309b" git push origin ``` -------------------------------- ### Implement Civilized Objects with Semantic Validation in C# Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Demonstrates how to create domain entities inheriting from `CivilizedObject` to enforce business rules and semantic correctness using `WildExceptions()` and `ThrowIfNotCivilized()`. It includes validation via DataAnnotations and custom rules, ensuring objects remain in a valid state throughout their lifecycle. ```csharp using PPWCode.Vernacular.Semantics.V; using PPWCode.Vernacular.Exceptions.V; using System.ComponentModel.DataAnnotations; // Define a domain entity that extends CivilizedObject public class Customer : CivilizedObject { [Required] [StringLength(100, MinimumLength = 2)] public string? Name { get; set; } [Required] [EmailAddress] public string? Email { get; set; } public override CompoundSemanticException WildExceptions() { // Start with base validation (DataAnnotations) CompoundSemanticException cse = base.WildExceptions(); // Add custom business rules if (Name?.Contains("test", StringComparison.OrdinalIgnoreCase) == true) { cse.AddElement(new SemanticException("Customer name cannot contain 'test'")); } return cse; } } // Usage example var customer = new Customer { Name = "J", Email = "invalid-email" }; Console.WriteLine($"Is Civilized: {customer.IsCivilized}"); // false var exceptions = customer.WildExceptions(); foreach (var ex in exceptions.Elements) { Console.WriteLine($"Validation error: {ex.Message}"); } // Output: Validation errors for Name length and Email format customer.Name = "John Doe"; customer.Email = "john@example.com"; customer.ThrowIfNotCivilized(); // Passes - object is now civilized ``` -------------------------------- ### AbstractFactory for Scoped Service Execution in C# Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Demonstrates the AbstractFactory pattern for creating and executing services within isolated Dependency Injection scopes. This is particularly useful for background tasks or multi-tenant applications where service lifecycles need to be managed independently. It requires Microsoft.Extensions.DependencyInjection. ```csharp using PPWCode.Util.DI.I; using Microsoft.Extensions.DependencyInjection; // Define a scoped service public interface IOrderProcessor { Task ProcessOrderAsync(Guid orderId, CancellationToken ct); } public class OrderProcessor : IOrderProcessor { private readonly IOrderRepository _repository; public OrderProcessor(IOrderRepository repository) { _repository = repository; } public async Task ProcessOrderAsync(Guid orderId, CancellationToken ct) { // Process order... } } // Factory that creates services in isolated scopes public class OrderProcessingFactory : AbstractFactory { public OrderProcessingFactory(IServiceProvider serviceProvider) : base(serviceProvider) { } // Create instance in current scope public IOrderProcessor CreateProcessor() => Create(); // Execute in new isolated scope (useful for background jobs) public async Task ProcessOrderInNewScopeAsync( Guid orderId, CancellationToken ct = default) { await ExecuteInNewScopeAsync( async (processor, token) => await processor.ProcessOrderAsync(orderId, token), cancellationToken: ct); } // Execute with context in new scope public async Task ValidateOrderInNewScopeAsync( Guid orderId, ValidationContext context, CancellationToken ct = default) { return await ExecuteInNewScopeAsync( async (processor, ctx, token) => { // Use context for validation... return true; }, context, cancellationToken: ct); } } // Setup and usage var services = new ServiceCollection(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); var provider = services.BuildServiceProvider(); var factory = provider.GetRequiredService(); // Process orders in isolated scopes (each gets fresh DbContext, etc.) await factory.ProcessOrderInNewScopeAsync(Guid.NewGuid()); ``` -------------------------------- ### Collection Diff Utilities for Comparing Collections (C#) Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt The `CollectionExtensions` class provides utility methods for comparing collections and calculating differences. It includes functions like `BagEqual` for order-insensitive equality, `SetEqual` for duplicate-insensitive equality, and `CalcDiff` to determine added, removed, and unchanged items between two collections. It also offers `ExecDiff` to perform actions based on these differences. ```csharp using PPWCode.Util.Collection.I; // Compare collections for equality var list1 = new[] { 3, 1, 2 }; var list2 = new[] { 1, 2, 3 }; var list3 = new[] { 1, 2, 2, 3 }; Console.WriteLine($"Bag equal (order ignored): {list1.BagEqual(list2)}"); // true Console.WriteLine($"Set equal (duplicates ignored): {list1.SetEqual(list3)}"); // true // Calculate differences between collections var currentItems = new[] { "A", "B", "C" }; var targetItems = new[] { "B", "C", "D", "E" }; DiffResult diff = currentItems.CalcDiff(targetItems); Console.WriteLine($"New items: {string.Join(", ", diff.NewItems)}"); // D, E Console.WriteLine($"Obsolete items: {string.Join(", ", diff.ObsoleteItems)}"); // A Console.WriteLine($"Unchanged items: {string.Join(", ", diff.IntersectedItems)}"); // B, C // Execute actions based on diff currentItems.ExecDiff( targetItems, newAction: item => Console.WriteLine($"Adding: {item}"), obsoleteAction: item => Console.WriteLine($"Removing: {item}"), intersectedAction: item => Console.WriteLine($"Keeping: {item}")); // Output: // Adding: D // Adding: E // Removing: A // Keeping: B // Keeping: C ``` -------------------------------- ### Switch Git Submodule to a Different Tag Source: https://github.com/peopleware/net-ppwcode-vnext/blob/main/README.md Commands to change the submodule to a different specific tag. This involves navigating into the submodule directory, checking out the desired tag, and then committing this change to the main repository. ```shell cd ppwcode-vnext git checkout preview/20250309f cd .. git commit -m "Switch ppwcode-vnext to preview/20250309f" ``` -------------------------------- ### Utilize PersistentObject Base Class for Entity Identity in C# Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Shows how to use the `PersistentObject` base class for entities requiring identity-based equality. It covers handling transient (unpersisted) and persistent states, proper hash code management, and identity comparison for entities with a specified ID type. ```csharp using PPWCode.Vernacular.Persistence.V; // Define a persistent entity with long ID public class Product : PersistentObject { public string Name { get; set; } = string.Empty; public decimal Price { get; set; } } // Transient entity (not yet saved) var product1 = new Product { Name = "Widget", Price = 29.99m }; Console.WriteLine($"Is Transient: {product1.IdIsTransient}"); // true // Persisted entity (after save, ID assigned) var product2 = new Product { Id = 1, Name = "Widget", Price = 29.99m }; Console.WriteLine($"Is Transient: {product2.IdIsTransient}"); // false // Identity comparison var product3 = new Product { Id = 1, Name = "Updated Widget", Price = 39.99m }; Console.WriteLine($"Same entity: {product2.IsSame(product3)}"); // true (same ID) Console.WriteLine($"Equal: {product2.Equals(product3)}"); // true // Type-safe casting IPersistentObject entity = product2; Product? typed = entity.As(); ``` -------------------------------- ### SyncCollection for Bidirectional Relationships (C#) Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt The `SyncCollection` class manages bidirectional relationships between parent and child entities. It automatically synchronizes back-references when items are added to or removed from the collection, simplifying the management of parent-child links in object models. ```csharp using PPWCode.Util.Collection.I; // Parent entity with synchronized collection public class Department { private SyncCollection? _employees; public SyncCollection Employees => _employees ??= new SyncCollection( this, (employee, dept) => employee.SetDepartment(dept)); public string Name { get; set; } = string.Empty; } // Child entity with back-reference public class Employee { private Department? _department; public string Name { get; set; } = string.Empty; public Department? Department => _department; // Internal method called by SyncCollection internal void SetDepartment(Department? dept) { SyncCollection.Set( this, ref _department, dept, d => d.Employees); } } // Usage - relationships stay synchronized var engineering = new Department { Name = "Engineering" }; var john = new Employee { Name = "John" }; var jane = new Employee { Name = "Jane" }; // Add to collection - back-reference is set automatically engineering.Employees.Add(john); Console.WriteLine($"John's dept: {john.Department?.Name}"); // Engineering engineering.Employees.Add(jane); Console.WriteLine($"Employee count: {engineering.Employees.Count}"); // 2 // Remove from collection - back-reference is cleared engineering.Employees.Remove(john); Console.WriteLine($"John's dept after removal: {john.Department?.Name}"); // null // Clear all - all back-references cleared engineering.Employees.Clear(); Console.WriteLine($"Jane's dept after clear: {jane.Department?.Name}"); // null ``` -------------------------------- ### Manage Time Periods with C# Period Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Utilizes the `Period` class and `PeriodHistory` for managing time periods. Supports overlap detection, intersection, and timeline queries. Requires PPWCode.Vernacular.Exceptions.V and PPWCode.Util.Time.I. ```csharp using PPWCode.Vernacular.Exceptions.V; using PPWCode.Util.Time.I; // Concrete DateOnly period implementation public class ContractPeriod : DateOnlyPeriod { public ContractPeriod() { } public ContractPeriod(DateOnly? from, DateOnly? to) : base(from, to) { } protected override SemanticException CreateInvalidExceptionFor(DateOnly? from, DateOnly? to) => new SemanticException($"Invalid contract period: {from} - {to}"); protected override IPeriod Create(DateOnly? from, DateOnly? to) => new ContractPeriod(from, to); } // Period history for managing timelines public class ContractHistory : PeriodHistory { public ContractHistory(params ContractPeriod[] periods) : base(periods) { } public ContractHistory(IEnumerable periods) : base(periods) { } protected override IPeriod Create(DateOnly? from, DateOnly? to) => new ContractPeriod(from, to); } // Usage examples var jan2024 = new ContractPeriod( new DateOnly(2024, 1, 1), new DateOnly(2024, 2, 1)); var feb2024 = new ContractPeriod( new DateOnly(2024, 2, 1), new DateOnly(2024, 3, 1)); var q1_2024 = new ContractPeriod( new DateOnly(2024, 1, 1), new DateOnly(2024, 4, 1)); // Period operations Console.WriteLine($"Jan contains Jan 15: {jan2024.Contains(new DateOnly(2024, 1, 15))}"); // true Console.WriteLine($"Jan overlaps Feb: {jan2024.Overlaps(feb2024)}"); // false (adjacent) Console.WriteLine($"Q1 contains Jan: {q1_2024.Contains(jan2024)}"); // true Console.WriteLine($"Jan within Q1: {jan2024.IsCompletelyContainedWithin(q1_2024)}"); // true // Period history with non-overlapping periods var history = new ContractHistory(jan2024, feb2024); // Query the timeline var periodAtJan15 = history.GetPeriodAt(new DateOnly(2024, 1, 15)); Console.WriteLine($"Period at Jan 15: {periodAtJan15}"); // [2024-01-01, 2024-02-01[ var overlapping = history.GetPeriodsOverlappingAt( new DateOnly(2024, 1, 15), new DateOnly(2024, 2, 15)); Console.WriteLine($"Overlapping periods: {overlapping.Count}"); // 2 // Period with open-ended dates (null = infinity) var openEnded = new ContractPeriod(new DateOnly(2024, 1, 1), null); Console.WriteLine($"Open-ended period: {openEnded}"); // [2024-01-01, +∞[ ``` -------------------------------- ### Update Git Submodule to Latest Commit Source: https://github.com/peopleware/net-ppwcode-vnext/blob/main/README.md A simple command to update the submodule to the latest commit or tag it is currently pointing to. This is typically run when pulled commits include changes to submodules. ```shell git submodule update ``` -------------------------------- ### CompoundSemanticException for Multiple Validation Errors (C#) Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt The `CompoundSemanticException` class aggregates multiple validation errors. It allows adding individual `SemanticException` instances, including nested compound exceptions, and provides methods to check for errors and iterate through them. This is useful for comprehensive error reporting in validation scenarios. ```csharp using PPWCode.Vernacular.Exceptions.V; // Collect multiple validation errors var compound = new CompoundSemanticException("Validation failed"); // Add individual errors compound.AddElement(new PropertyException("Name", "Name is required")); compound.AddElement(new PropertyException("Email", "Invalid email format")); compound.AddElement(new ValueException("Age must be positive")); // Check if there are errors if (!compound.IsEmpty) { Console.WriteLine($"Error count: {compound.Count}"); // 3 // Iterate over errors foreach (SemanticException ex in compound.Elements) { Console.WriteLine($"Error: {ex.Message}"); } // Close and throw compound.Close(); throw compound; } // Nest compound exceptions (elements are flattened) var outer = new CompoundSemanticException(); var inner = new CompoundSemanticException(); inner.AddElement(new SemanticException("Inner error 1")); inner.AddElement(new SemanticException("Inner error 2")); outer.AddElement(inner); // Flattens into outer Console.WriteLine($"Outer count: {outer.Count}"); // 2 // Check for specific error types bool hasNameError = compound.ContainsElement( new PropertyException("Name", "Name is required")); ``` -------------------------------- ### Validate IBANs with C# IBAN Class Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Validates International Bank Account Numbers (IBANs) against ISO 13616 standards for over 70 countries. Includes checksum validation and provides electronic and paper formats. Requires PPWCode.Util.Validation.IV. ```csharp using PPWCode.Util.Validation.IV; // Create and validate IBAN IBAN belgianIban = "BE68 5390 0754 7034"; Console.WriteLine($"Is Valid: {belgianIban.IsValid}"); // true Console.WriteLine($"Country: {belgianIban.Country}"); // BE Console.WriteLine($"Electronic: {belgianIban.ElectronicVersion}"); // BE68539007547034 Console.WriteLine($"Paper: {belgianIban.PaperVersion}"); // BE68 5390 0754 7034 // Convert Belgian IBAN to BBAN var bban = belgianIban.AsBBAN; Console.WriteLine($"BBAN: {bban?.ElectronicVersion}"); // 539007547034 // Implicit conversion from string IBAN germanIban = "DE89370400440532013000"; Console.WriteLine($"German IBAN valid: {germanIban.IsValid}"); // true // Invalid IBAN IBAN invalid = "XX00 0000 0000 0000"; Console.WriteLine($"Invalid IBAN valid: {invalid.IsValid}"); // false // Access country information var countryInfo = IBAN.IBANCountryInformation["NL"]; Console.WriteLine($"NL IBAN length: {countryInfo.IBANLength}"); // 18 Console.WriteLine($"NL BBAN pattern: {countryInfo.Pattern}"); // 4a,10n ``` -------------------------------- ### Validate Belgian INSS with C# INSS Class Source: https://context7.com/peopleware/net-ppwcode-vnext/llms.txt Validates and parses Belgian National Register Numbers (INSS). Extracts birthdate and sex, supporting both pre-2000 and post-2000 formats, including BIS numbers. Requires PPWCode.Util.Validation.IV.European.Belgium. ```csharp using PPWCode.Util.Validation.IV.European.Belgium; // Validate INSS number INSS inss = "85.07.30-001.33"; Console.WriteLine($"Is Valid: {inss.IsValid}"); // true Console.WriteLine($"Electronic: {inss.ElectronicVersion}"); // 85073000133 Console.WriteLine($"Paper: {inss.PaperVersion}"); // 85.07.30-001.33 // Extract information from valid INSS if (inss.IsValid) { Console.WriteLine($"Birth Date: {inss.BirthDate:yyyy-MM-dd}"); // 1985-07-30 Console.WriteLine($"Sex: {inss.Sex}"); // MALE (odd counter = male) Console.WriteLine($"Is BIS Number: {inss.IsBisNumber}"); // false Console.WriteLine($"Is National Number: {inss.IsNationalNumber}"); // true } // BIS numbers (month > 12 indicates non-Belgian resident) INSS bisNumber = "85.27.30-001.06"; // Month 27 = 07 + 20 (BIS indicator) Console.WriteLine($"Is BIS Number: {bisNumber.IsBisNumber}"); // true // Implicit conversion INSS fromString = "93122935781"; Console.WriteLine($"Valid 1993 INSS: {fromString.IsValid}"); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.