. NET application architecture design-work unit model (get rid of the important idea of Procedural Code and attack DDD against it)
Reading directory:
1. Background introduction 2. True dilemmas of Procedural Code 3. Simple examples of the work unit Mode 4. Summary 1. Background introduction
I have been talking about object-oriented development all the time. However, when developing enterprise application systems, the biggest problem with object-oriented development is that the interoperability between multiple objects requires database operations. Two business logic objects need to be called to each other. If the mutual operation is within the scope of a business transaction, it is easy to complete, however, if this business logic operation involves collaboration between multiple business objects, the problem arises.
In the past, we used procedural code (transaction Script Mode) to write all the logic related to the scope of this business transaction in a large code, even if you extract repeated code properly, the effect is not very good, because you will never be able to get rid of the dilemma of multi-object operations. To determine whether you are in this dilemma, you only need to check that all your transaction operations have only one business method at the entry point. For example, when you add an order, you also process the items that follow the order in the "add order" method, instead of in another "add ORDER item" method, these two methods are located in different table module classes.
This chapter describes a mode that is used to coordinate multiple business objects within a single business transaction scope when developing an enterprise application system to ensure a complete transaction.
2. Procedural Code dilemmas
In fact, the biggest difference between developing an application system and developing a framework or component is to consider data persistence, and the persistence logic is closely related to the business logic, the final action of a method may be to add a row of data or update a field. Instead, the code of the application system often refreshes the final persistent file in a unified manner at the end, and such programs seldom perform transactional data operations. Even if yes, it is relatively simple to use memory for transaction processing, so there is no need to consider so many services.
I have also written many components and frameworks before. Although there is nothing complicated, my experience and sentiment is how to use the detailed design granularity in enterprise application systems, how to carry out complex and meticulous OO design and development. In fact, if we cannot break the pattern of procedural code, looking at more OO Knowledge is also insufficient, which will lead to a lot of negative emotions (because I have had this experience ).
In fact, we still lack the correct method. In this article, the UnitOfWork mode will help us get out of the process-based business logic and move towards at least object-oriented development. With UnitOfWork, you can use the Table module, Activa Record, and Domin Driven modes at will, and you can divide SOA (CQRS) on a large layout based on your project needs ), each mode can be used to its full potential in a suitable scenario.
3. simple example of the work unit Mode
Here we still use the simple order shopping business as an example. After all, everyone understands this part of the business concept. The business layer of this instance uses the Active Record mode.
namespace OrderManager.Business{ using System.Collections.Generic; public partial class Order { public long OId { get; set; } public List
Products { get; set; } }}
The Field Section of the Order activity record object.
Namespace OrderManager. business {public partial class Order {public bool CheckOrder () {// execute some Business verification work if (this. OId <= 0) return false; return true ;}}}
The Order activity record object is used purely for demonstration and contains a simple judgment business logic.
namespace OrderManager.Business{ public partial class OrderProducts { public long OrderId { get; set; } public long PId { get; set; } public float Price { get; set; } }}
Partial Order item field.
Namespace OrderManager. business {public partial class OrderProducts {public bool CheckProducts () {// execute some Business verification work if (this. orderId <= 0) return false; return true ;}}}
Each item contains its own logic verification.
Next, let's take a look at how the entry method at the application layer coordinates business operations and data storage between two activity record objects.
Namespace OrderManager {using OrderManager. business; using OrderManager. dataSource; public class OrderManagerController: ControllerBase {public bool AddOrder (Order order) {using (UnitOfWork unitOfWork = new UnitOfWork () {Order. checkOrder (); // run the business Check order. products. forEach (item => {item. checkProducts (); // run the business check of each activity record object. The table module can also be used for processing. }); OrderGateway orderGateway = new OrderGateway (unitOfWork); var orderDbResult = orderGateway. addOrder (order); // The first database table operation OrderProductsGateway productGateway = new OrderProductsGateway (unitOfWork); var productDbResult = productGateway. addOrderProducts (order. products); // The second database table operation if (orderDbResult & productDbResult) {if (unitOfWork. commit () {this. sendOrderIntegrationMssage (order); // The message indicating that the integration order is successfully sent. Return true;} this. pushOrderProcessQueue (order); // send this order to the processing queue and return false;} this. logBusinessException (order); // record a service exception LOG for troubleshooting. Return false ;}}}}
For a simple demonstration, I directly construct a Data Access Object using instantiation. In actual use, I can use the IOC tool for Dynamic Injection.
Let's take a look at the data layer code. I use the table entry mode for the data layer.
namespace OrderManager.DataSource{ public abstract class GatewayBase { protected UnitOfWork UnitOfWork { get; private set; } public GatewayBase(UnitOfWork unit) { this.UnitOfWork = unit; } public bool Commit() { return this.UnitOfWork.Commit(); } public void Rollback() { this.UnitOfWork.Rollback(); } }}
This is a base table entry class.
Namespace OrderManager. dataSource {using OrderManager. business; public class OrderGateway: GatewayBase {public OrderGateway (UnitOfWork unit): base (unit) {} public bool AddOrder (Order order) {// you can directly operate the database using the SQL concatenation method you are familiar with, without the need for an ORM. Return true ;}}}
Namespace OrderManager. dataSource {using OrderManager. business; using System. collections. generic; public class OrderProductsGateway: GatewayBase {public OrderProductsGateway (UnitOfWork unit): base (unit) {} public bool AddOrderProducts (List
Products) {// you can directly operate the database by concatenating SQL statements that you are familiar with, without the need for ORM. Return true ;}}}
This is an entry object for two tables. In fact, this part of the code is quite familiar to everyone, so I omitted it here. You can directly splice an SQL statement to insert it into the database.
namespace OrderManager.DataSource{ using System; public class UnitOfWork : IDisposable { public void Dispose() { throw new NotImplementedException(); } public bool Commit() { return true; } public void Rollback() { // } }}
The UnitOfWrok object is actually an encapsulation of the System. Data. Common. DbConnection object of the database object. Here you can use the method you are familiar with to construct the database connection object and start transactions.
What we really appreciate is the code in the application controller. Here, we can coordinate and process various logics, and finally record some necessary logs and send some integrated messages. Did you find that you can process some business systems without using DDD.
4. Summary
In fact, I think the activity record mode + Table Entry Mode + work unit mode can handle small and medium business logic very well. With the current SOA-based architecture, there are very few large projects in one solution.
Finally, I would like to provide a reference. If you are interested, you can further discuss the specific design. This is the time-related article. Thank you.