Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Canonical mode-From ABP Document

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)06/01 Report--

Introduction

A canonical pattern is a specific software design pattern that can be reassembled by linking business rules together using Boolean logic (Wikipedia).

In practice, it is mainly used to define reusable filters for entities or other business objects.

Example

In this section, we will see that specification patterns are required. This section is generic and has nothing to do with the implementation of ABP.

Suppose you have a service method to calculate the total number of customers, as follows:

Public class CustomerManager {public int GetCustomerCount () {/ / TODO... Return 0;}}

You may want to get the number of customers through the filter. For example, you may have advanced customers (with a balance of more than $100000), or you may want to filter customers by registering for the year. You can then create other methods, such as GetPremiumCustomerCount (), GetCustomerCountRegisteredInYear (int year), GetPremiumCustomerCountRegisteredInYear (int year), and so on. Because you have more standards, you cannot create a combination for each possibility.

One solution to this problem is the canonical pattern. We can create a method that gets parameters as a filter:

Public class CustomerManager {private readonly IRepository _ customerRepository; public CustomerManager (IRepository customerRepository) {_ customerRepository = customerRepository;} public int GetCustomerCount (ISpecification spec) {var customers = _ customerRepository.GetAllList (); var customerCount = 0; foreach (var customer in customers) {if (spec.IsSatisfiedBy (customer)) {customerCount++ }} return customerCount;}}

Therefore, we can get any object as a parameter to implement the ISpecification interface, defined as follows:

Public interface ISpecification {bool IsSatisfiedBy (T obj);}

We can call IsSatisfiedBy with the customer to test whether the customer is interested. Therefore, we can use the same GetCustomerCount and different filters without changing the method itself.

Although this solution is quite good in theory, it should be improved to work better in C#. For example, it is inefficient to get all customers provided from the database to check whether they meet the given specifications / conditions. In the next section, we will see the implementation of ABP that overcomes this problem.

Create a canonical class

ABP defines the ISpecification interface, as follows:

Public interface ISpecification {bool IsSatisfiedBy (T obj); Expression To_Expression ();}

Add the ToExpression () method, which returns an expression and is used for better integration with IQueryable and Expression trees. Therefore, we can easily pass the specification to the repository to apply the filter at the database level.

We usually inherit from the canonical class rather than directly implementing the ISpecification interface. The specification class automatically implements the IsSatisfiedBy method. So, we just need to define ToExpression. Let's create some canonical classes:

/ / Customers with $1000000 + balance are assumed as PREMIUM customers.public class PremiumCustomerSpecification: Specification {public override Expression To_Expression () {return (customer) = > (customer.Balance > = 100000);}} / / A parametric specification example.public class CustomerRegistrationYearSpecification: Specification {public int Year {get;} public CustomerRegistrationYearSpecification (int year) {Year = year;} public override Expression To_Expression () {return (customer) = > (customer.CreationYear = = Year);}}

As you can see, we just implemented a simple lambda expression to define the specification. Let's use these specifications to get the number of customers:

Count = customerManager.GetCustomerCount (new PremiumCustomerSpecification ()); count = customerManager.GetCustomerCount (new CustomerRegistrationYearSpecification (2017)); usage specification and repository

Now we can optimize CustomerManager to apply filters in the database:

Public class CustomerManager {private readonly IRepository _ customerRepository; public CustomerManager (IRepository customerRepository) {_ customerRepository = customerRepository;} public int GetCustomerCount (ISpecification spec) {return _ customerRepository.Count (spec.To_Expression ());}}

This is simple and we can pass any specification to the repository because the repository can use expressions as filters. In this example, CustomerManager is unnecessary because we can query the database directly using a repository with specifications. But I think we want to perform business operations on some customers. In this case, we can use a specification with domain services to specify the customer to work.

Write specifications

A powerful feature of the specification is that they can be combined with AND,OR, not with the ANDNOT extension method. Example:

Var count = customerManager.GetCustomerCount (new PremiumCustomerSpecification () .And (new CustomerRegistrationYearSpecification (2017)

We can even create a new specification class from an existing specification:

Public class NewPremiumCustomersSpecification: AndSpecification {public NewPremiumCustomersSpecification (): base (new PremiumCustomerSpecification (), new CustomerRegistrationYearSpecification (2017)) {}}

The specification is a subclass of the Specification class and can only be satisfied if both specifications are satisfied. Then we can use NewPremiumCustomersSpecification like other specifications:

Var count = customerManager.GetCustomerCount (new NewPremiumCustomersSpecification ())

Discuss

Although canonical patterns are older than C#lambda expressions, they are usually compared to expressions. Some developers may think that it is no longer needed, and we can pass the expression directly to the repository or domain service, as shown below:

Var count = _ customerRepository.Count (c = > c.Balance > 100000 & & c.CreationYear = = 2017)

Because ABP's repository supports expessions, this is a fully effective usage. You don't have to define or use any specifications in your application, you can use expressions. So what does it mean? Why and when should you consider using them?

When will it be used?

Some of the benefits of using specifications:

Reusabe: think you need to use PremiumCustomer filters in many places in your code base. If you use expressions instead of creating specifications, what happens if you later change the definition of "advanced customer" (for example, to change the final balance from $100000 to $250000 and add another condition to become a customer over 3 years old). If you use the specification, you only need to change a single class. If you use (copy / paste) the same expressions, you need to change them.

Combinable: you can combine multiple specifications to create new specifications. This is another kind of reusability.

Naming: PremiumCustomerSpecification is a better explanation of intentions than complex expressions. Therefore, if your business has meaningful expressions, consider using specifications.

Testable: a specification is a separate (and easily) testable object.

When not to use it?

Non-business expressions: you can consider specifications that do not use non-business-related expressions and operations.

Report: if you are just creating a report, instead of creating a specification, use IQueryable directly. In fact, you can even report using simple SQL,Views or other tools. DDD doesn't care about reporting, and from a performance perspective, the query advantage of the underlying data store may be important.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report