-
Notifications
You must be signed in to change notification settings - Fork 13
Queries
Queries are requests to external system that does not change their data state. In ideal world queries are pure functions (idempotent - user receive same result with each call), but in reality this is not possible. Two consequent queries may return different data. It depends on outer system's behavior.
Thing that we actually have to ensure - that our logic does not perform any update on outer systems. Tecture tries to ensure it when possible, but often it is not. E.g.: you may perform direct SQL queries to the database that actuall do UPDATE
. But you better to do not. Tecture cannot ensure it technically, so unfortunately it relies on you.
Queries in tecture are being performed as extension methods to channel's read end:
var user = From<Db>().All<User>().FirstOrDefault(x=>x.Id == 10);
var order = From<Db>().SqlQuery<Order>(x=>$"SELECT * FROM {x}").As<Order>().First();
Both .All<>
and .SqlQuery<>
are extension (static) methods provided by the aspect. They return their own abstractions that you also may use and create own extension methods.
Example: generic ById
method performed using ORM aspect. My favorite one:
public interface IEntity { Id {get;} }
public static class Extensions
{
///<summary>
/// This method will stick to all .Get<T> invokations when T implements IEntity
///</summary>
public static T ById<T>(this IQueryFor<T> q, int id) where T : IEntity
{
return q.All.FirstOrDefault(x => x.Id == id);
}
}
Query extensions can be placed everywhere. Their intention is to replace read abstractions (Repositories) in software design. Try to avoid creating services with Get*
methods and put query functionality into extensions.
In order to perform query you need to obtain reading channel end. You can do that using From<>
method. It can be located within service or ITecture
instance.
Example: query from the service
public class Orders : TectureService<Order>, INoContext
{
private Orders() { }
public void MarkAsDraft(int orderId)
{
var order = From<Db>.Get<Order>().ById(orderId);
To<Db>.Update(order)
.Set(x=>x.Name, order.Name + " (draft)")
}
}
Example: query from MVC controller
public class OrdersController : ApiController
{
private readonly ITecture _tecture;
public OrdersController(ITecture tecture)
{
_tecture = tecture;
}
public ActionResult PerformActionWithOrder(int id)
{
var orders = _tecture.From<Db>()
.All<Orders>()
.Where(x => x.Status == Status.Active)
.Select(x => new {x.Id, x.Name})
.ToArray();
return Json(orders);
}
}
(c) 2020, Pavel B. Novikov