Business Central query objects enable you to retrieve records from one or more tables and then combine the data into rows and columns in a single dataset. Query objects can also perform calculations on data, such finding the sum or average of all values in a column of the dataset.
A query pattern defines an example phrase a user might say. The Assistant can match user spoken phrases that are semantically similar using natural language processing. Query patterns can contain a literal string, conditionals, and arguments using Schema.org types.
A Query Object is an interpreter [Gang of Four], that is, a structure of objects that can form itself into a SQL query. You can create this query by refer-ring to classes and fields rather than tables and columns.
Why use a design pattern? The usefulness of using a design pattern is obvious. The design pattern can accelerate the development process. It provides proven development paradigms, which helps save time without having to reinvent patterns every time a problem arises.
The Query design pattern is usually used in combination with the Repository design pattern.
Let us go with an example and then I will give a nice article to read. Let's say that we have a database where we store information about our customers and their orders, etc.
Then we create an initial repository like this:
class CustomerRepository() {
Customer GetById(int id) { // implementation }
void DeleteCustomer(int id) { // impl }
Customer GetCustomerWithOrder(int orderId);
Customer[] GetCustomersWithOrdersMoreThan(int numberOfOrders);
}
As you can see for every query we created a method in the repository which is very fine and well for limited number of queries but when we have a lot of them and they start getting complicated with a lot of combinations (e.g. get me customers with purchases that exceed 1000 and live in New York and their credit limit is less than 3000) then we will end up with a long list of methods and even worse, leaking some business logic in the shape of queries inside the repositories which we don't want to happen.
So to refactor that we change the repository to something like this:
class CustomerRepository() {
Customer[] Get(Query query) { // implementation }
void DeleteCustomer(int id) { // impl }
}
As you can see we are passing a Query Object which represents our query in the form of an object and the repository has one and only repository to execute that query and give us the results back.
Now how implement that query object and how to build it will require a lot of code so at this point i will direct you over to this nice article. It is in C# but you will find it very helpful, also you can look at the Criteria API (Java) which is used by NHibernate to see a different but similar implementation.
The Query Object represented a query written in the language of the domain and was an implementation of the Query Object pattern. The Query Object pattern as described by Fowler is “an object that represents a database query.” Without some mechanism of querying, the Repository would be awash with myriad retrieval methods such as can be seen in this code snippet:
public interface ICustomerRepository
{
IEnumerable<Customer> FindAll();
IEnumerable<Customer> FindAllVIPCustomers();
IEnumerable<Customer> FindByOrder(Guid ID);
IEnumerable<Customer> FindAllCustomersThatHaveOutstandingOrders();
…
}
Instead, the Query Object enables any query to be constructed and then sent to the Repository to be satisfied. The major benefit of the Query Object pattern is that it completely abstracts away the underlying database querying language and thus keeps the infrastructure concerns of data persistence and retrieval out of the business layer. At some point, however, the raw querying language of the database needs to be created; this is achieved using a database-specific QueryTranslator that takes the Query Objects and converts them into the language of the database.
From Pro ASP.NET Design Patterns book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With