Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/guide/durability/polecat/event-sourcing.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ public class MarkItemReady
}
```

::: tip
The Polecat integration recognizes both its own `Wolverine.Polecat.IdentityAttribute` and the
shared `JasperFx.IdentityAttribute` used elsewhere in the Critter Stack (and by the
[Marten integration](../marten/event-sourcing)). If you maintain a single, store-agnostic
command/aggregate source that is compiled against both Marten and Polecat, decorate the identity
member with the shared `JasperFx.IdentityAttribute` (i.e. `using JasperFx;`) and it will be honored
by both stores — no per-store attribute alias is required.
:::

## Forwarding Events

See [Event Forwarding](./event-forwarding) for more information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ public void determine_aggregate_id_with_identity_attribute_help()
.Name.ShouldBe(nameof(RejectPcInvoice.Something));
}

[Fact]
public void determine_aggregate_id_with_shared_jasperfx_identity_attribute()
{
// Regression for #3117 -- Polecat should honor the shared JasperFx.IdentityAttribute
// used across the rest of the Critter Stack (and Marten), not just its own [Identity].
AggregateHandling.DetermineAggregateIdMember(typeof(PcInvoice), typeof(RejectPcInvoiceShared))
.Name.ShouldBe(nameof(RejectPcInvoiceShared.Something));
}

[Fact]
public void determine_aggregate_id_with_identity_attribute_bypass()
{
Expand Down Expand Up @@ -155,6 +164,10 @@ public record PcInvoiceCreated;

public record RejectPcInvoice([property: Identity] Guid Something);

// Uses the shared JasperFx.IdentityAttribute (fully qualified to bypass the
// file-level alias pinning [Identity] to Wolverine.Polecat.IdentityAttribute).
public record RejectPcInvoiceShared([property: JasperFx.Identity] Guid Something);

public class PcInvoiceHandler
{
public PcInvoiceCreated Handle(CreatePcInvoice command)
Expand Down
9 changes: 7 additions & 2 deletions src/Persistence/Wolverine.Polecat/AggregateHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,12 @@ internal static void ValidateMethodSignatureForEmittedEvents(IChain chain, Metho
internal static MemberInfo DetermineAggregateIdMember(Type aggregateType, Type commandType)
{
var conventionalMemberName = $"{aggregateType.Name}Id";
var member = commandType.GetMembers().FirstOrDefault(x => x.HasAttribute<IdentityAttribute>())

// Honor both the Polecat-specific [Identity] and the shared JasperFx.IdentityAttribute
// used across the rest of the Critter Stack (and Marten) so a single store-agnostic
// command/aggregate source can codegen against both stores.
var member = commandType.GetMembers().FirstOrDefault(x =>
x.HasAttribute<IdentityAttribute>() || x.HasAttribute<JasperFx.IdentityAttribute>())
?? commandType.GetMembers().FirstOrDefault(x =>
x.Name.EqualsIgnoreCase(conventionalMemberName) || x.Name.EqualsIgnoreCase("Id"));

Expand All @@ -197,7 +202,7 @@ internal static MemberInfo DetermineAggregateIdMember(Type aggregateType, Type c
if (member == null)
{
throw new InvalidOperationException(
$"Unable to determine the aggregate id for aggregate type {aggregateType.FullNameInCode()} on command type {commandType.FullNameInCode()}. Either make a property or field named '{conventionalMemberName}', or decorate a member with the {typeof(IdentityAttribute).FullNameInCode()} attribute");
$"Unable to determine the aggregate id for aggregate type {aggregateType.FullNameInCode()} on command type {commandType.FullNameInCode()}. Either make a property or field named '{conventionalMemberName}', or decorate a member with the {typeof(IdentityAttribute).FullNameInCode()} or {typeof(JasperFx.IdentityAttribute).FullNameInCode()} attribute");
}

return member;
Expand Down
Loading