The documentation comes from the Markdown files in the source code, so is always up-to-date but available only in English. Enjoy!
AutoExpressionField is the main pattern in Signum Framework for defining calculated properties on entities or methods with reusable query fragments. It allows you to encapsulate calculations or query logic in a single place, making them available both in-memory and in LINQ queries.
You can use [AutoExpressionField] on a property to define its logic with As.Expression, making it available both in-memory and in LINQ queries.
Example: Scalar Calculation
public class OrderEntity : Entity
{
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
[AutoExpressionField]
public decimal TotalPrice => As.Expression(() => UnitPrice * Quantity);
}expressionProperty snippet to save some keystrokes.You can also use [AutoExpressionField] on static extension methods to encapsulate reusable query fragments.
Example: Query Fragment (IQueryable as Extension Method)
public static class CustomerLogic
{
[AutoExpressionField]
public static IQueryable<OrderEntity> Orders(this CustomerEntity c) =>
As.Expression(() => Database.Query<OrderEntity>()
.Where(o => o.Customer.Is(c));
}expressionMethod or expressionMethodQuery snippet to save some keystrokes.You can now use customer.Orders() inside your LINQ queries or directly from a loaded entity.
If you want to expose this method in the UI (e.g., SearchControl, charts, templates), you need to register it as described below.
While properties in entities are automatically discovered, methods in static classes need to be registered to be available in the UI (e.g., SearchControl, charts, templates). To do this, register the expression using:
sb.Include<CustomerEntity>()
.WithExpression(c => c.Orders());This will add a new option in the SearchControl for CustomerEntity for the method to be used as a query token in the UI.
Since Orders will be used in the UI it needs to be translated. In this simple case it uses the NicePluralName of the target type (e.g. if the UI is in spanish will be "Pedidos").
Other cases might require a custom name, for eaxmple:
public static class CustomerLogic
{
[AutoExpressionField]
public static IQueryable<OrderEntity> RecentOrders(this CustomerEntity c) =>
As.Expression(() => c.Orders().Where(o => o.OrderDate > DateTime.Now.AddMonths(-1)));
}Could be registered doing:
sb.Include<CustomerEntity>()
.WithExpression(c => c.RecentOrders(), OrdersMessage.RecentOrders);Internally, WithExpression uses QueryLogic.Expressions.Register to register the expression.
The main overloads for registering expressions are:
public ExtensionInfo Register<E, S>(Expression<Func<E, S>> lambdaToMethodOrProperty, Func<string>? niceName = null)
public ExtensionInfo Register<E, S>(Expression<Func<E, S>> lambdaToMethodOrProperty, Enum niceName)
public ExtensionInfo Register<E, S>(Expression<Func<E, S>> extensionLambda, Func<string> niceName, string key, bool replace = false)Typically, you only need the first overload for most scenarios.
You can further customize the metadata of the registered expression using the returned ExtensionInfo object.
Internally, [AutoExpressionField] pattern is translated by Signum.MSBuildTask to using the [ExpressionField] attribute and a generated static expression field.
public class OrderEntity : Entity
{
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public static Expression<Func<OrderEntity, decimal>> TotalPriceExpression =
o => o.UnitPrice * o.Quantity;
[ExpressionField(nameof(TotalPriceExpression))]
public decimal TotalPrice => TotalPriceExpression.Evaluate(this);
}Then, the LINQ provider uses TotalPriceExpression for translating queries, while in-memory evaluation uses the TotalPrice property.
In most cases, you should use AutoExpressionField for simplicity and consistency. However, you can use [ExpressionField] directly for advanced scenarios where you want to separate the database and in-memory implementations. This is useful, for example, when you want to use cached entities in-memory but generate an expression for database queries.
Example: Separate In-Memory and DB Logic Using Lite.Entity
public class OrderEntity : Entity
{
public Lite<CustomerEntity> Customer { get; set; }
public static Expression<Func<OrderEntity, string>> CustomerNameExpression =
o => o.Customer.Entity.Name; //Used in queries
[ExpressionField(nameof(CustomerNameExpression))]
public string CustomerName => this.Customer.RetrieveFromCache().Name; // Used in-memory,
}© Signum Software. All Rights Reserved.
Powered by Signum Framework