CHR0019: Projection expression lambda must only access members
Rule Description
Section titled “Rule Description”Expression lambdas passed to projection builder methods (e.g. Set(x => ...), To(e => ...), IdentifiedBy(x => ...), UsingKey(e => ...)) must only contain simple member access. They cannot contain method calls, arithmetic, conditional expressions, or any other executable code.
Severity
Section titled “Severity”Error
Example
Section titled “Example”Violation
Section titled “Violation”using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
public class Chr0019UserReadModel{ public string Name { get; set; } = string.Empty;}
[EventType]public record Chr0019UserRegistered(string Name);
public class Chr0019UserProjection : IProjectionFor<Chr0019UserReadModel>{ public void Define(IProjectionBuilderFor<Chr0019UserReadModel> builder) => builder.From<Chr0019UserRegistered>(_ => _ .Set(x => x.Name) .To(e => e.Name.ToUpper())); // CHR0019: method call - never executed}using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
public class Chr0019UserReadModelFixed{ public string Name { get; set; } = string.Empty;}
[EventType]public record Chr0019UserRegisteredFixed(string Name);
public class Chr0019UserProjectionFixed : IProjectionFor<Chr0019UserReadModelFixed>{ public void Define(IProjectionBuilderFor<Chr0019UserReadModelFixed> builder) => builder.From<Chr0019UserRegisteredFixed>(_ => _ .Set(x => x.Name) .To(e => e.Name)); // Now valid - simple member access}Why This Rule Exists
Section titled “Why This Rule Exists”In Chronicle’s projection builder, any parameter typed as Expression<Func<...>> is parsed at startup to extract a property path for the read-model mapping—the lambda body is never executed at runtime. Writing method calls, arithmetic (e.Count + 1), conditional expressions (e.Flag ? e.A : e.B), or similar executable code in such a lambda will be silently ignored, producing an incorrect or incomplete projection definition that is very difficult to debug.
The only valid lambda body is a direct property access chain, for example x => x.Property or x => x.Parent.Child.