Browse pages
LS1010: Repository Exposes a Query Surface
LS1010 is a compiler check that reports a repository interface in Domain, the layer that holds business rules, that exposes a query surface such as IQueryable or a database session. A repository loads and stores one aggregate, and a query surface would let any caller compose its own queries around the rules the aggregate protects. This page states what the rule reports, where the error sits, and how to return aggregates and Domain types only.
Reference#
What the Rule Enforces#
LS1010 enforces Keep repository interfaces in Domain (litespec/backend/dotnet/domain#keep-repository-interfaces-in-domain). It runs in Domain only. Its category is LiteSpec.Domain. Severity and enablement follow the Analyzers overview.
What the Rule Reports#
The rule reports an interface whose name ends in Repository when it is generic over a type parameter its members use, or when a member exposes IQueryable, a type derived from it, a member type whose name ends in Session, DbContext, or DbSet without deriving the project's AggregateRoot<>, or an Expression<Func<...>> parameter. The diagnostic sits on the interface name for a generic surface. For any other breach it sits on the offending member type.
Failing Example#
public interface IOrderRepository
{
IQueryable<Order> Query();
}Passing Example#
public interface IOrderRepository
{
Task<Order?> FindAsync(OrderId id, CancellationToken cancellationToken);
}How to Fix#
Return aggregates and Domain types only from the repository, and move query composition to a query handler that reads through IQuerySession.
Notes#
What the Rule Ignores#
The rule does not report interfaces whose names do not end in Repository, or members that return aggregates and Domain types such as Task<Order?> FindAsync(OrderId id, CancellationToken cancellationToken). An aggregate that derives AggregateRoot<> never breaches the name test, even when its name ends in Session, DbContext, or DbSet. It does not run outside Domain.