### Install Polecat.AspNetCore NuGet Package Source: https://polecat.jasperfx.net/llms-full.txt Install the Polecat.AspNetCore NuGet package using the dotnet CLI. ```bash dotnet add package Polecat.AspNetCore ``` -------------------------------- ### ProjectLatest with string-keyed streams Source: https://polecat.jasperfx.net/llms-full.txt This example shows how to use ProjectLatest with streams that are identified by string keys instead of GUIDs. ```csharp // For stores configured with StreamIdentity.AsString session.Events.StartStream("report-123", new ReportCreated("Annual Report"), new SectionAdded("Overview") ); var report = await session.Events.ProjectLatest("report-123"); ``` -------------------------------- ### Example: Appending and Aggregating Events Source: https://polecat.jasperfx.net/llms-full.txt Shows how to append events to start a new stream and then aggregate those events to reconstruct the stream's state. Verifies event sourcing functionality. ```csharp public class EventStoreTests : IntegrationContext { [Fact] public async Task can_append_and_aggregate() { Guid streamId; await using (var session = OpenSession()) { streamId = session.Events.StartStream( new QuestStarted("Test Quest"), new MembersJoined("Start", ["Alice", "Bob"]) ); await session.SaveChangesAsync(); } await using (var session = QuerySession()) { var party = await session.Events.AggregateStreamAsync(streamId); party.ShouldNotBeNull(); party.Members.Count.ShouldBe(2); } } } ``` -------------------------------- ### Start a Stream and Append Initial Events Source: https://polecat.jasperfx.net/events/quickstart Initialize the Polecat DocumentStore and start a new event stream with initial events using a lightweight session. ```csharp var store = DocumentStore.For(opts => { opts.Connection("Server=localhost,1433;Database=myapp;User Id=sa;Password=YourStrong!Password;TrustServerCertificate=True"); }); await using var session = store.LightweightSession(); // Start a new stream with initial events var questId = session.Events.StartStream( new QuestStarted("Destroy the Ring"), new MembersJoined("Rivendell", ["Frodo", "Sam", "Aragorn", "Gandalf"]) ); await session.SaveChangesAsync(); ``` -------------------------------- ### Starting a New Event Stream Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to create a new event stream with initial events. Supports explicit GUID, auto-generated, and string stream IDs. ```csharp // With explicit ID var streamId = Guid.NewGuid(); session.Events.StartStream(streamId, new QuestStarted("Destroy the Ring"), new MembersJoined("Rivendell", ["Frodo", "Sam"]) ); // With auto-generated ID var streamId = session.Events.StartStream( new QuestStarted("Destroy the Ring") ); // String stream IDs (when StreamIdentity = AsString) session.Events.StartStream("quest-123", new QuestStarted("Destroy the Ring") ); ``` -------------------------------- ### Seed Initial Data on Startup Source: https://polecat.jasperfx.net/llms-full.txt Registers a data seeding operation to run when the application starts. This example stores a new User object. ```csharp opts.InitialData.Add(async (store, ct) => { await using var session = store.LightweightSession(); session.Store(new User { FirstName = "Admin", LastName = "User" }); await session.SaveChangesAsync(ct); }); ``` -------------------------------- ### Integration Test Setup with Polecat Cleanup Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to use `CleanAllDocumentsAsync` and `CleanAllEventDataAsync` in an integration test's setup (`InitializeAsync`) to ensure a clean slate for each test run. Requires implementing `IAsyncLifetime`. ```cs public class MyTests : IAsyncLifetime { private IDocumentStore _store = null!; public async Task InitializeAsync() { _store = DocumentStore.For(opts => { ... }); // Clean slate for each test await _store.Advanced.CleanAllDocumentsAsync(); await _store.Advanced.CleanAllEventDataAsync(); } public async Task DisposeAsync() { await _store.DisposeAsync(); } } ``` -------------------------------- ### Install Polecat EntityFrameworkCore Package Source: https://polecat.jasperfx.net/events/projections/efcore Use the dotnet CLI to add the Polecat.EntityFrameworkCore package to your project. ```shell dotnet add package Polecat.EntityFrameworkCore ``` -------------------------------- ### Example MCP Request to Call Tool Source: https://polecat.jasperfx.net/llms-full.txt An example cURL request to the MCP endpoint to call the 'get_event_store_configuration' tool. Ensure the Content-Type is application/json. ```bash curl -X POST http://localhost:5000/polecat/mcp/ \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_event_store_configuration" } }' ``` -------------------------------- ### Example: Storing and Loading a Document Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to store a User document and then load it back using the IntegrationContext. Ensures the document is correctly persisted and retrieved. ```csharp public class UserStorageTests : IntegrationContext { [Fact] public async Task can_store_and_load_document() { var user = new User { FirstName = "Alice", LastName = "Smith" }; await using (var session = OpenSession()) { session.Store(user); await session.SaveChangesAsync(); } await using (var session = QuerySession()) { var loaded = await session.LoadAsync(user.Id); loaded.ShouldNotBeNull(); loaded.FirstName.ShouldBe("Alice"); } } } ``` -------------------------------- ### Install Polecat Package (Package Manager Console) Source: https://polecat.jasperfx.net/llms-full.txt Use the Package Manager Console in Visual Studio to install the Polecat package. ```powershell PM> Install-Package Polecat ``` -------------------------------- ### Example Polecat Schema SQL Output Source: https://polecat.jasperfx.net/llms-full.txt This is an example of the SQL script generated by Polecat, showing `CREATE TABLE` statements for various schema components like streams, events, event progression, and user documents. ```sql -- Polecat Schema Script CREATE TABLE dbo.pc_streams ( id uniqueidentifier NOT NULL PRIMARY KEY, type nvarchar(250) NULL, version int NOT NULL DEFAULT 0, ... ); CREATE TABLE dbo.pc_events ( seq_id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY, id uniqueidentifier NOT NULL, stream_id uniqueidentifier NOT NULL, ... ); CREATE TABLE dbo.pc_event_progression ( name nvarchar(250) NOT NULL PRIMARY KEY, last_seq_id bigint NOT NULL DEFAULT 0, ... ); CREATE TABLE dbo.pc_doc_user ( id uniqueidentifier NOT NULL PRIMARY KEY, data json NOT NULL, ... ); ``` -------------------------------- ### Install Polecat Package (.NET CLI) Source: https://polecat.jasperfx.net/llms-full.txt Use the .NET CLI to add the Polecat package to your project. ```shell dotnet add package Polecat ``` -------------------------------- ### Guid IDs for Multi Stream Projection Source: https://polecat.jasperfx.net/llms-full.txt Example of configuring a MultiStreamProjection with Guid as the ID type. ```csharp // Guid IDs public class MyProjection : MultiStreamProjection { } ``` -------------------------------- ### Query Using a Simple Index Source: https://polecat.jasperfx.net/llms-full.txt Example of querying for a user by their UserName, leveraging the previously defined index for performance. ```cs var user = await session.Query() .FirstOrDefaultAsync(x => x.UserName == "somebody"); ``` -------------------------------- ### Quick Example: Appending and Replaying Events Source: https://polecat.jasperfx.net/events Define events, append them to a new stream, and then replay the stream to reconstruct the aggregate state. This demonstrates a basic event sourcing workflow. ```csharp // Define events public record InvoiceCreated(decimal Amount, string Customer); public record InvoicePaid(decimal AmountPaid, DateTimeOffset PaidAt); // Append events await using var session = store.LightweightSession(); var streamId = session.Events.StartStream( new InvoiceCreated(100m, "Acme Corp"), new InvoicePaid(100m, DateTimeOffset.UtcNow) ); await session.SaveChangesAsync(); // Replay to aggregate var invoice = await session.Events.AggregateStreamAsync(streamId); ``` -------------------------------- ### Example MCP Response for Tool Call Source: https://polecat.jasperfx.net/llms-full.txt An example JSON response from the MCP server after successfully calling a tool. The 'result.content' field contains the tool's output. ```json { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"streamIdentity\":\"AsGuid\",\"tenancyStyle\":\"Single\",\"databaseSchemaName\":\"dbo\",...}" } ] } } ``` -------------------------------- ### Lightweight Session Example Source: https://polecat.jasperfx.net/documents/sessions Opens a lightweight session with no identity tracking. Each LoadAsync call returns a new object instance. ```csharp await using var session = store.LightweightSession(); ``` -------------------------------- ### Install Polecat.AspNetCore NuGet Package Source: https://polecat.jasperfx.net/llms-full.txt Install the Polecat.AspNetCore NuGet package using the Package Manager Console. This package provides helpers for ASP.NET Core development. ```powershell PM> Install-Package Polecat.AspNetCore ``` -------------------------------- ### Strongly-Typed Guid IDs Usage Source: https://polecat.jasperfx.net/documents/identity Demonstrates storing, loading, querying, and deleting documents using strongly-typed Guid IDs. Ensure the session and query objects are properly initialized. ```csharp // Store with auto-assigned Guid wrapper var order = new Order { Name = "Widget" }; session.Store(order); await session.SaveChangesAsync(); // order.Id is now assigned // Load by inner value var loaded = await query.LoadAsync(order.Id.Value); // LINQ queries work with the wrapper type directly var result = await query.Query() .Where(x => x.Id == order.Id) .FirstOrDefaultAsync(); // IsOneOf for multiple IDs var results = await query.Query() .Where(x => x.Id.IsOneOf(id1, id2, id3)) .ToListAsync(); // Delete by inner value session.Delete(order.Id.Value); // Check existence var exists = await query.CheckExistsAsync(order.Id.Value); ``` -------------------------------- ### Independent Event Sequences with Per-Tenant Partitioning Source: https://polecat.jasperfx.net/events/multitenancy Illustrates how event sequences start independently for different tenants when per-tenant event partitioning is enabled. Each tenant's sequence begins at 1. ```csharp // Each tenant's seq_id starts at 1 and advances independently await using var red = store.LightweightSession(new SessionOptions { TenantId = "Red" }); red.Events.StartStream(redStream, new QuestStarted("Red")); // Red seq_id 1 await red.SaveChangesAsync(); await using var blue = store.LightweightSession(new SessionOptions { TenantId = "Blue" }); blue.Events.StartStream(blueStream, new QuestStarted("Blue")); // Blue seq_id 1 — independent await blue.SaveChangesAsync(); ``` -------------------------------- ### Implement IPolecatLogger for Session Logging Source: https://polecat.jasperfx.net/llms-full.txt Implement IPolecatLogger at the store level to create per-session loggers. This example shows a console logger. ```csharp public class ConsolePolecatLogger : IPolecatLogger { public IPolecatSessionLogger StartSession(IQuerySession session) { return new ConsoleSessionLogger(); } } public class ConsoleSessionLogger : IPolecatSessionLogger { public void OnBeforeExecute(string sql) { Console.WriteLine($"Executing: {sql}"); } public void LogSuccess(string sql) { Console.WriteLine($"Success: {sql}"); } public void LogFailure(string sql, Exception ex) { Console.WriteLine($"Failed: {sql} - {ex.Message}"); } public void RecordSavedChanges(IDocumentSession session) { Console.WriteLine($"Saved changes ({session.RequestCount} requests)"); } } ``` -------------------------------- ### Strongly Typed ID Usage Examples Source: https://polecat.jasperfx.net/llms-full.txt Shows how to use strongly typed IDs with Polecat operations like storing, loading, querying, and deleting documents. ```cs // Store with auto-assigned Guid wrapper var order = new Order { Name = "Widget" }; session.Store(order); await session.SaveChangesAsync(); // order.Id is now assigned // Load by inner value var loaded = await query.LoadAsync(order.Id.Value); // LINQ queries work with the wrapper type directly var result = await query.Query() .Where(x => x.Id == order.Id) .FirstOrDefaultAsync(); // IsOneOf for multiple IDs var results = await query.Query() .Where(x => x.Id.IsOneOf(id1, id2, id3)) .ToListAsync(); // Delete by inner value session.Delete(order.Id.Value); // Check existence var exists = await query.CheckExistsAsync(order.Id.Value); ``` -------------------------------- ### Define a Reusable Query Plan Source: https://polecat.jasperfx.net/documents/querying/batched-queries Implement IBatchQueryPlan to define a reusable query specification. This example defines a plan for active orders. ```csharp public class ActiveOrdersPlan : QueryListPlan { protected override IQueryable Query(IQuerySession session) { return session.Query().Where(x => x.Status == "Active"); } } ``` -------------------------------- ### Query Session Example Source: https://polecat.jasperfx.net/documents/sessions Opens a query session for read-only operations. This session type cannot store or delete documents. ```csharp await using var session = store.QuerySession(); ``` -------------------------------- ### Identity Map Session Example Source: https://polecat.jasperfx.net/documents/sessions Opens an identity map session that tracks loaded documents by ID. Repeated loads of the same document return the same instance. ```csharp await using var session = store.OpenSession(DocumentTracking.IdentityMap); ``` -------------------------------- ### LINQ to SQL Translation Example Source: https://polecat.jasperfx.net/documents/querying/linq Illustrates how LINQ queries are translated into SQL using JSON_VALUE for property extraction. ```sql SELECT data FROM pc_doc_user WHERE JSON_VALUE(data, '$.lastName') = @p0 ORDER BY JSON_VALUE(data, '$.firstName') ``` -------------------------------- ### Basic Live Aggregation Usage Source: https://polecat.jasperfx.net/events/projections/live-aggregates Loads all events for a stream and applies them through the aggregate's Create and Apply methods. Use this to get the current state of an aggregate. ```csharp var order = await session.Events.AggregateStreamAsync(streamId); ``` -------------------------------- ### SQL Translation Example Source: https://polecat.jasperfx.net/llms-full.txt Illustrates the SQL query generated by Polecat for a LINQ query involving filtering and ordering. Shows how `JSON_VALUE` is used to access JSON properties. ```sql SELECT data FROM pc_doc_user WHERE JSON_VALUE(data, '$.lastName') = @p0 ORDER BY JSON_VALUE(data, '$.firstName') ``` -------------------------------- ### Store and Save a Document Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to create a document instance, store it within a session, and persist the changes to the database. ```csharp // Store a document await using var session = store.LightweightSession(); var user = new User { FirstName = "Jane", LastName = "Doe", Email = "jane@example.com" }; session.Store(user); await session.SaveChangesAsync(); ``` -------------------------------- ### Bulk Insert with Custom Batch Size Source: https://polecat.jasperfx.net/llms-full.txt Allows control over the number of documents processed in each batch. The default is 200; this example sets it to 500. Adjusting batch size can optimize performance based on document size and server resources. ```cs await store.Advanced.BulkInsertAsync(users, BulkInsertMode.InsertsOnly, batchSize: 500); ``` -------------------------------- ### Guid Identity (Default) Source: https://polecat.jasperfx.net/documents/identity When the 'Id' property is Guid.Empty, Polecat automatically assigns a new Guid upon storing the document. ```csharp public class User { public Guid Id { get; set; } public string Name { get; set; } = ""; } ``` -------------------------------- ### Implementing IConfigurePolecat Source: https://polecat.jasperfx.net/configuration/hostbuilder Shows how to implement IConfigurePolecat for modular configuration and register it before AddPolecat(). ```csharp public class MyPolecatConfig : IConfigurePolecat { public void Configure(IServiceProvider services, StoreOptions options) { // Apply configuration here } } ``` ```csharp builder.Services.AddSingleton(); builder.Services.AddPolecat(options => { options.Connection("..."); }); ``` -------------------------------- ### Starting a New Stream with String IDs Source: https://polecat.jasperfx.net/events/appending Use this when your StreamIdentity is configured as AsString to start a new stream with a string ID. ```csharp session.Events.StartStream("quest-123", new QuestStarted("Destroy the Ring") ); ``` -------------------------------- ### Automatic Guid ID Assignment Source: https://polecat.jasperfx.net/llms-full.txt When using `Guid` IDs, they are automatically assigned if the ID is `Guid.Empty` upon calling `Store()` or `Insert()`. ```cs var user = new User(); // Id is Guid.Empty session.Store(user); // Id is now assigned ``` -------------------------------- ### Basic Bulk Insert Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates the basic usage of the Bulk Insert API to insert a list of user objects. Ensure the 'store' object is initialized. ```cs var users = Enumerable.Range(0, 1000) .Select(i => new User { FirstName = $"User{i}", LastName = "Bulk" }) .ToList(); await store.Advanced.BulkInsertAsync(users); ``` -------------------------------- ### Store and Query Documents with Polecat Source: https://polecat.jasperfx.net/documents Demonstrates storing a new 'User' document using a session, saving changes, loading a document by its ID, and querying documents using LINQ expressions. ```csharp // Define a document public class User { public Guid Id { get; set; } public string FirstName { get; set; } = ""; public string LastName { get; set; } = ""; public string Email { get; set; } = ""; } // Store a document await using var session = store.LightweightSession(); var user = new User { FirstName = "Jane", LastName = "Doe", Email = "jane@example.com" }; session.Store(user); await session.SaveChangesAsync(); // Load by ID var loaded = await session.LoadAsync(user.Id); // Query with LINQ var users = await session.Query() .Where(x => x.LastName == "Doe") .ToListAsync(); ``` -------------------------------- ### ProjectLatest (Guid ID) Source: https://polecat.jasperfx.net/llms-full.txt Returns the projected state of an aggregate including pending events, identified by a Guid. This method is useful for scenarios where you need the most up-to-date state immediately after appending events without committing them. ```APIDOC ## ProjectLatest (Guid ID) ### Description Retrieves the projected state of an aggregate, including any events that have been appended in the current session but not yet committed. This is useful for getting an immediate projected result after appending events without needing to force a save and re-fetch. ### Method `ValueTask ProjectLatest(Guid id, CancellationToken cancellation = default)` ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Assuming 'session' is an instance of IDocumentSession var report = await session.Events.ProjectLatest(Guid.NewGuid()); ``` ### Response #### Success Response - **T?**: The projected aggregate state, including pending events. Returns null if the aggregate does not exist. #### Response Example ```json { "example": "report object" } ``` ``` -------------------------------- ### Create Standalone Document Store Source: https://polecat.jasperfx.net/getting-started Instantiate a DocumentStore outside of the generic host infrastructure using the static DocumentStore.For() method, providing the connection string. ```csharp var store = DocumentStore.For("Server=localhost;Database=myapp;User Id=sa;Password=YourStrong!Password;TrustServerCertificate=True"); ``` -------------------------------- ### Int IDs for Multi Stream Projection Source: https://polecat.jasperfx.net/llms-full.txt Example of configuring a MultiStreamProjection with int as the ID type. ```csharp // Int IDs public class MyProjection : MultiStreamProjection { } ``` -------------------------------- ### Configuring Separate Database Tenancy Source: https://polecat.jasperfx.net/events/multitenancy Sets up a DocumentStore where each tenant is assigned its own independent database. This provides complete data isolation between tenants. ```csharp var store = DocumentStore.For(opts => { opts.MultiTenantedDatabases(databases => { databases.AddSingleTenantDatabase("Server=localhost;Database=events_tenant_a;...", "tenant-a"); databases.AddSingleTenantDatabase("Server=localhost;Database=events_tenant_b;...", "tenant-b"); }); }); ``` -------------------------------- ### String IDs for Multi Stream Projection Source: https://polecat.jasperfx.net/llms-full.txt Example of configuring a MultiStreamProjection with string as the ID type. ```csharp // String IDs public class MyProjection : MultiStreamProjection { } ``` -------------------------------- ### Storing and Querying Documents with Polecat Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to configure Polecat as a document store, store a .NET object as a JSON document, and query documents using LINQ. Ensure the connection string is correctly set. ```csharp var store = DocumentStore.For(opts => { opts.ConnectionString = connectionString; opts.UseNativeJsonType = true; // SQL Server 2025 JSON column type }); await using var session = store.LightweightSession(); session.Store(new Customer { Id = id, Name = "Acme", Region = "EMEA" }); await session.SaveChangesAsync(); await using var query = store.QuerySession(); var emea = await query.Query() .Where(x => x.Region == "EMEA") .OrderBy(x => x.Name) .ToListAsync(); ``` -------------------------------- ### Aggregate Count with LINQ Source: https://polecat.jasperfx.net/documents/querying/linq Use CountAsync to get the total number of documents matching the query. ```cs var count = await session.Query().CountAsync(); ``` -------------------------------- ### Guid Versioning Column Source: https://polecat.jasperfx.net/llms-full.txt Includes a column for GUID-based versioning, typically used when implementing the IVersioned interface. ```sql guid_version uniqueidentifier NULL ``` -------------------------------- ### Registering Multi-Stream Projections Source: https://polecat.jasperfx.net/events/projections/multi-stream-projections Demonstrates how to register a multi-stream projection for either immediate (inline) or background (async) processing. ```csharp // Inline — projected immediately during SaveChangesAsync opts.Projections.Add(ProjectionLifecycle.Inline); // Async — projected by the async daemon in the background opts.Projections.Add(ProjectionLifecycle.Async); ``` -------------------------------- ### Explicitly Setting Expected Version Source: https://polecat.jasperfx.net/documents/concurrency Shows how to explicitly set the expected Guid version for concurrency checks before saving. ```csharp session.UpdateExpectedVersion(order, expectedGuidVersion); ``` -------------------------------- ### Configure DocumentStore Connection Source: https://polecat.jasperfx.net/getting-started Configure the connection string for the DocumentStore. Ensure to replace placeholder values with your actual database credentials. ```csharp var store = DocumentStore.For(opts => { opts.Connection("Server=localhost;Database=myapp;User Id=sa;Password=YourStrong!Password;TrustServerCertificate=True"); // Configure additional options... }); ``` -------------------------------- ### Typical Command Handler for PlaceOrder Source: https://polecat.jasperfx.net/llms-full.txt This C# snippet shows a typical command handler for placing an order. It uses attributes like [AggregateHandler] and [WriteAggregate] to leverage Wolverine.Polecat's code generation for state management, abstracting away direct database operations. ```csharp public class PlaceOrderHandler { [AggregateHandler] public static OrderPlaced Handle(PlaceOrder cmd, [WriteAggregate] Order order) { if (order.Status != OrderStatus.Draft) throw new InvalidOperationException("Order is not in draft state."); return new OrderPlaced(cmd.CustomerId, cmd.LineItems); } } ``` -------------------------------- ### Search for LastName starting with 'Sm' Source: https://polecat.jasperfx.net/llms-full.txt Uses the StartsWith method to find users whose last name begins with 'Sm'. ```cs var results = session.Query() .Where(x => x.LastName.StartsWith("Sm")) .ToListAsync(); ``` -------------------------------- ### Querying Monthly Account Activity Source: https://polecat.jasperfx.net/events/projections/multi-stream-projections Shows how to query projected monthly account summaries, including retrieving all summaries for an account and loading a specific month's summary. ```csharp // Get all monthly summaries for an account var monthlies = await session.Query() .Where(x => x.AccountId == accountId) .OrderBy(x => x.Month) .ToListAsync(); // Get a specific month var jan = await session.LoadAsync($"{accountId}:2026-01"); ``` -------------------------------- ### Starting a New Stream with Auto-Generated ID Source: https://polecat.jasperfx.net/events/appending Use this to create a new event stream where the ID is automatically generated by the system. ```csharp var streamId = session.Events.StartStream( new QuestStarted("Destroy the Ring") ); ``` -------------------------------- ### Register Async Projection for Monthly Activity Source: https://polecat.jasperfx.net/llms-full.txt Register the `MonthlyAccountActivityProjection` to run asynchronously. This allows the projection to be processed by the background daemon for eventual consistency. ```csharp // Async — projected by the async daemon in the background opts.Projections.Add(ProjectionLifecycle.Async); ``` -------------------------------- ### Starting a New Stream with Explicit ID Source: https://polecat.jasperfx.net/events/appending Use this to create a new event stream with a predefined ID and initial events. ```csharp var streamId = Guid.NewGuid(); session.Events.StartStream(streamId, new QuestStarted("Destroy the Ring"), new MembersJoined("Rivendell", ["Frodo", "Sam"]) ); ``` -------------------------------- ### Configure Dynamic Tenant Management with Master Table Source: https://polecat.jasperfx.net/configuration/multitenancy Set up dynamic tenant management by specifying a master table strategy. This requires a control-plane database to store tenant-connection string mappings and allows runtime updates without restarting the service. ```csharp var store = DocumentStore.For(opts => { // Default/fallback connection opts.Connection("..."); // The control-plane database that holds the pc_tenants registry opts.MultiTenantedMasterTable("Server=localhost;Database=control_plane;..."); }); ``` -------------------------------- ### Configure Stream Identity Source: https://polecat.jasperfx.net/events Configure the event store to use either Guid or string for stream IDs. This is set during the DocumentStore configuration. ```csharp var store = DocumentStore.For(opts => { opts.Connection("..."); // Default: Guid stream IDs opts.Events.StreamIdentity = StreamIdentity.AsGuid; // Alternative: String stream IDs opts.Events.StreamIdentity = StreamIdentity.AsString; }); ``` -------------------------------- ### Configuring Polecat and Wolverine Integration Source: https://polecat.jasperfx.net/llms-full.txt This C# snippet demonstrates how to configure Polecat and integrate it with Wolverine at the composition root. It includes setting the connection string, configuring live stream aggregation for the Order aggregate, and enabling the transactional outbox and handler code generation. ```csharp builder.Services.AddPolecat(opts => { opts.ConnectionString = connectionString; opts.Projections.LiveStreamAggregation(); }) .IntegrateWithWolverine(); // transactional outbox + handler codegen ``` -------------------------------- ### CountBy Equivalent using GroupBy Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to achieve the functionality of `CountBy` using `GroupBy` and `Select` for SQL translation. This is the recommended approach for server-side counting. ```cs // Translated to SQL: select count(*), color ... group by color var counts = await session.Query() .GroupBy(x => x.Color) .Select(g => new { Color = g.Key, Count = g.Count() }) .ToListAsync(); ``` -------------------------------- ### Apply Store Policies Source: https://polecat.jasperfx.net/llms-full.txt Applies store-wide or document-specific policies. Example shows soft deletion for all documents and a specific document type. ```csharp opts.Policies.AllDocumentsSoftDeleted(); opts.Policies.ForDocument(mapping => { mapping.DeleteStyle = DeleteStyle.SoftDelete; }); ``` -------------------------------- ### Use a Query Plan in a Batch Source: https://polecat.jasperfx.net/llms-full.txt Adds a query operation using a predefined `IBatchQueryPlan` to the batch. This leverages the reusable query specification. ```cs // Use in a batch var ordersTask = batch.QueryByPlan(new ActiveOrdersPlan()); await batch.Execute(); var orders = await ordersTask; ``` -------------------------------- ### Basic LINQ Filter and Order Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates a simple LINQ query to filter users by last name and order them by first name. Assumes `User` class and `session` object are available. ```cs // Simple filter var smiths = await session.Query() .Where(x => x.LastName == "Smith") .ToListAsync(); // With ordering var sorted = await session.Query() .OrderBy(x => x.LastName) .ThenBy(x => x.FirstName) .ToListAsync(); ``` -------------------------------- ### WriteToAggregate Example Source: https://polecat.jasperfx.net/events/appending Applies and saves events to an aggregate in a single operation. Use when you need to fetch, modify, and persist events atomically. ```csharp await session.Events.WriteToAggregate(streamId, stream => { stream.AppendOne(new MembersDeparted("Mordor", ["Frodo", "Sam"])); }); await session.SaveChangesAsync(); ``` -------------------------------- ### Create a Batch Query Source: https://polecat.jasperfx.net/documents/querying/batched-queries Initialize a new batch query session. ```csharp var batch = session.CreateBatchQuery(); ``` -------------------------------- ### Custom Session Factory Registration Source: https://polecat.jasperfx.net/configuration/hostbuilder Example of registering Polecat with a custom ISessionFactory to change session behavior, such as enabling identity tracking. ```csharp builder.Services.AddPolecat(options => { options.Connection("..."); }); ``` -------------------------------- ### Multi Stream Projection with EF Core Source: https://polecat.jasperfx.net/events/projections/efcore Implement a multi stream projection using EfCoreMultiStreamProjection. This example projects OrderCreated events into a CustomerDashboard. ```csharp public class CustomerEfProjection : EfCoreMultiStreamProjection { public CustomerEfProjection() { Identity(e => e.CustomerId); } public CustomerDashboard Create(OrderCreated e, AppDbContext db) { return new CustomerDashboard { TotalOrders = 1, TotalSpent = e.Amount }; } public void Apply(OrderCreated e, CustomerDashboard current, AppDbContext db) { current.TotalOrders++; current.TotalSpent += e.Amount; } } ``` -------------------------------- ### Multi-Stream Projection with Different ID Types Source: https://polecat.jasperfx.net/events/projections/multi-stream-projections Illustrates how multi-stream projections can be defined to support various aggregate ID types, such as Guid, string, or int. ```csharp // Guid IDs public class MyProjection : MultiStreamProjection { } // String IDs public class MyProjection : MultiStreamProjection { } // Int IDs public class MyProjection : MultiStreamProjection { } ``` -------------------------------- ### Session Options Configuration Source: https://polecat.jasperfx.net/documents/sessions Configures a lightweight session with various options including multi-tenancy, command timeout, metadata tracking, and custom listeners. ```csharp await using var session = store.LightweightSession(new SessionOptions { // Multi-tenancy TenantId = "my-tenant", // Command timeout in seconds Timeout = 30, // Metadata tracking CorrelationId = "request-123", CausationId = "command-456", LastModifiedBy = "user@example.com", // Per-session listeners Listeners = { new MySessionListener() } }); ``` -------------------------------- ### Registering EF Core Projections Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates how to register EF Core projections for inline or asynchronous processing. ```csharp opts.Projections.Add(ProjectionLifecycle.Inline); // or opts.Projections.Add(ProjectionLifecycle.Async); ``` -------------------------------- ### Self-Aggregating Document Type Example Source: https://polecat.jasperfx.net/llms-full.txt Defines a self-aggregating document type 'QuestParty' with static Create and instance Apply methods, which is required for Snapshot() registration. ```cs public class QuestParty { public Guid Id { get; set; } public string Name { get; set; } = ""; public List Members { get; set; } = new(); public static QuestParty Create(QuestStarted e) => new() { Name = e.Name }; public void Apply(MembersJoined e) => Members.AddRange(e.Members); } ``` -------------------------------- ### Add Polecat with Async Daemon Source: https://polecat.jasperfx.net/getting-started Configure Polecat for async projections and opt the daemon into the host. This snippet shows how to register async projections and enable the solo daemon mode. ```csharp builder.Services.AddPolecat(options => { options.Connection("..."); options.Projections.Add(ProjectionLifecycle.Async); }) .ApplyAllDatabaseChangesOnStartup() .AddAsyncDaemon(DaemonMode.Solo); ``` -------------------------------- ### Single Stream Projection with EF Core Source: https://polecat.jasperfx.net/events/projections/efcore Implement a single stream projection using EfCoreSingleStreamProjection. This example shows creating and applying changes to OrderReadModel. ```csharp public class OrderEfProjection : EfCoreSingleStreamProjection { public OrderReadModel Create(OrderCreated e, OrderDbContext db) { var model = new OrderReadModel { Status = "Created", Amount = e.Amount }; db.Orders.Add(model); return model; } public void Apply(OrderShipped e, OrderReadModel current, OrderDbContext db) { current.Status = "Shipped"; current.ShippedDate = e.ShippedAt; } } ``` -------------------------------- ### Polecat Registration with Pre-built StoreOptions Source: https://polecat.jasperfx.net/llms-full.txt Registers Polecat services using a pre-configured `StoreOptions` object. This is useful when options are built elsewhere. ```cs // Pre-built StoreOptions var storeOptions = new StoreOptions(); storeOptions.Connection("..."); builder.Services.AddPolecat(storeOptions); ``` -------------------------------- ### Store, Load, and Delete with Natural Keys Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates standard document operations (store, load, delete) using a natural key defined with the [Identity] attribute. ```csharp // Store var customer = new Customer { CustomerCode = "CUST-001", Name = "Acme" }; session.Store(customer); await session.SaveChangesAsync(); // Load by the identity value var loaded = await query.LoadAsync("CUST-001"); // Delete session.Delete("CUST-001"); ``` -------------------------------- ### Snapshot Projection Lifecycles Source: https://polecat.jasperfx.net/llms-full.txt Demonstrates registering a Snapshot projection with either the Inline or Async lifecycle. Inline updates occur in the same transaction, while Async updates are handled by the projection daemon. ```cs // Updated in the same transaction as the appended events opts.Projections.Snapshot(SnapshotLifecycle.Inline); // Updated asynchronously by the async projection daemon opts.Projections.Snapshot(SnapshotLifecycle.Async); ``` -------------------------------- ### Register a Flat Table Projection Source: https://polecat.jasperfx.net/events/projections/flat Registers a defined flat table projection with the application options for asynchronous processing. Ensure this is done during application setup. ```csharp opts.Projections.Add(ProjectionLifecycle.Async); ``` -------------------------------- ### Using Event Metadata in Projections Source: https://polecat.jasperfx.net/llms-full.txt Provides an example of an EF Core projection that accesses event metadata, specifically the Timestamp and custom Headers, to populate its own properties. ```csharp public class OrderSummary { public Guid Id { get; set; } public DateTimeOffset CreatedAt { get; set; } public string? CreatedBy { get; set; } public void Apply(IEvent @event) { CreatedAt = @event.Timestamp; CreatedBy = @event.Headers?["user"]?.ToString(); } } ```