"Anatomy PetShop" bis: PetShop data access Layer Library access design _ self-study process

Source: Internet
Author: User
Tags abstract reflection static class

Database access design of PETSHOP data access layer

In series one, I analyze the architecture design of petshop as a whole, and mention the concept of layering. Starting with this section, I will analyze the layers in sequence, in order to get a more detailed and in-depth understanding. In PetShop 4.0, due to the introduction of some of the new features of ASP.net 2.0, the content of the data layer is also more extensive and complex, including: Database access, messaging, membership, profile four parts. In series two, I'll describe the design for database access.

In PetShop, the database objects that the system needs to deal with are divided into two types: one is the data entity and the corresponding data table in the corresponding database. They have no behavior and are used only to represent the data of the object. These entity classes are placed in the model assembly, such as the entity class OrderInfo for the order of the datasheet, whose class diagram is as follows:

These objects do not have a persistent function, simply, they are as a carrier of data, so that business logic for the corresponding data tables for read/write operations. Although the properties of these classes map the columns of the datasheet, and each instance of the object corresponds exactly to each row of the datasheet, these entity classes do not have the corresponding database access capabilities.

Because the data access layer and the business logic layer will operate on these data entities, the assembly model is referenced by the modules in the two tiers.

The second type of database object is the business logic object of the data. The business logic referred to here is not a domain (domain) business logic in the sense of the business logic (in this sense, I prefer to refer to the business logic layer as "domain Logic Layer"), in general, these business logic is basic database operations, including Select,insert, Update and delete. Because these business logic objects have only behavior and are not data-independent, they are abstracted as a separate interface module Idal, such as the interface for a datasheet order Iorder:

Separating the data entities from the related database operations conforms to the object-oriented spirit. First, it embodies the principle of "separation of duties". Separating the data entity from its behavior makes the dependency between the two weaken, and when the data behavior changes, it does not affect the data entity object in model module, avoids the "disastrous" effect of the reference of the class because of the excessive and too large responsibility of a class. Secondly, it embodies the spirit of "abstraction", or the best embodiment of "interface-oriented programming". Abstract interface Module Idal, complete isolation from the specific database access implementation. This design, which is independent of the implementation, ensures the scalability of the system and also ensures the portability of the database. In PetShop, SQL Server and Oracle can be supported, and their specific implementations are placed in two different modules Sqlserverdal, Oracledal respectively.

Take order as an example, in Sqlserverdal, oracledal two modules, there are different implementations, but they also implement the Iorder interface, as shown in the figure:

From the realization of the database, PetShop embodies the bloated and ugly without ORM framework. Because of the insert and select operations on the datasheet, for example, SQL Server uses objects such as Sqlcommand,sqlparameter,sqldatareader to complete these operations. Particularly complex is the parameter pass, in PetShop, a large number of string constants are used to hold the name of the parameter. In addition, PetShop provides an abstract helper class specifically for SQL Server and Oracle, wrapping some common operations, such as ExecuteNonQuery, ExecuteReader, and so on.

In the absence of ORM, using the helper class is a good strategy, using it to complete the basic operation of the database encapsulation, can reduce a lot of database operations related to the code, which embodies the principle of object reuse. PetShop these helper classes into the Dbutility module, the helper classes in different databases are exposed in the same way, except for a few special requirements, such as the way Oracle handles BOOL types, unlike SQL Server. Thus the orabit and Orabool methods are specifically provided. In addition, the methods in the helper class are static methods to facilitate invocation. Oraclehelper's class diagram is as follows:

For the data access layer, the biggest headache is the processing of SQL statements. In the early CS structure, the data access layer and the business logic layer are tightly blended together because the three-layer architecture design is not adopted, so the SQL statements are all over the corner of the system. This brings great difficulty to the maintenance of the program. In addition, because Oracle uses PL-SQL and SQL Server and Sybase use T-SQL, both of which follow standard SQL syntax, there is still a difference in many details, and if the SQL statement is used heavily in the program, There is no doubt that a possible database transplant also poses difficulties.

The best approach is to use stored procedures. This approach makes the program cleaner and easier to migrate and modify because stored procedures can exist in the form of database scripts. But this approach is still flawed. First, the test of stored procedures is relatively difficult. Although there is a corresponding debugging tool, but compared to the debugging of the code, it is still more complex and inconvenient. The second is to bring obstacles to the renewal of the system. If database access is done by a program, under the. NET platform, we only need to xcopy the recompiled assembly to the deployed server after modifying the program. If you use stored procedures, for security reasons, you must have a dedicated DBA to rerun the stored procedure script, and the way to deploy is limited.

I used to use a special table in a project to store SQL statements. To use a related SQL statement, use a keyword search to get the corresponding statement. This approach is similar to a call to a stored procedure, but avoids deployment problems. However, this approach is not guaranteed in terms of performance. It is only suitable for scenarios with fewer SQL statements. However, with good design, we can provide different tables for various businesses to store SQL statements. In the same way, these SQL statements can also be stored in the XML file, more conducive to the expansion or modification of the system. But the premise is that we need to provide it with a dedicated SQL statement management tool.

The use of SQL statements can not be avoided, how to better apply the SQL statement is inconclusive, but there is a principle worthy of our adherence, that is, "should try to make the SQL statements in the data access layer in the implementation of the concrete".

Of course, if you apply ORM, then everything will be different. Because the ORM framework has provided basic select,insert,update and delete operations for data access. For example, in NHibernate, we can invoke the Save method of the ISession object directly to insert (or create) a data entity object:

public void Insert (OrderInfo order)
{
 ISession s = sessions.getsession ();
 ITransaction trans = null;
 Try
 {
 trans = s.begintransaction ();
 S.save (order);
 Trans.commit ();
 }
 Finally
 {
 s.close ();
 }
}

There are no SQL statements, there are no annoying parameters, and there is no need to specifically consider the transaction. In addition, such a design is not related to the database, NHibernate can support different databases through the mechanism of dialect (dialect). The only thing to do is that we need to define HBM files for OrderInfo.

Of course, ORM Frameworks are not omnipotent, and in the face of complex business logic, it does not completely eliminate SQL statements and replaces complex database access logic, but it is a good representation of the "80/20 (or 90/10) rule" (also known as the "Pareto Rule"), which means that the flowers are less (10%- 20%) can solve most of the problems (80%-90%), and to solve the remaining small part of the problem will require much more effort. At the very least, with the most crud operations in the data access layer, by leveraging the ORM framework, we need only a handful of time and effort to solve them. This undoubtedly shortens the overall development cycle of the project.

Or go back to the discussion of PetShop. Now that we have the data entity, the abstract interface and implementation of the data object, it can be said that the main body of the database access has been completed. There are two issues left for us to solve:

1. Management of data object creation
2, facilitate the transplantation of the database

In PetShop, the data objects to be created include Order,product,category,inventory,item. In the previous design, these objects had been abstracted as corresponding interfaces, and their implementations differed according to the database. That is, there are many categories of objects created, and each category has a different implementation, which is a typical application scenario for abstract factory patterns. The two problems mentioned above can also be solved by the abstract factory model. The standard abstract factory pattern class diagram is as follows:

For example, the order object for creating SQL Server is as follows:

Petshopfactory factory = new Sqlserverfactory ();
Iorder = Factory. Createorder ();

To take into account the portability of the database, factory must act as a global variable and be instantiated when the main program is run. However, although this design has reached the "package change" purpose, but in the creation of Petshopfactory objects, there is still the inevitable emergence of a specific class sqlserverfactory, that is to say, The program has a strong dependency on this level with sqlserverfactory. Once the entire system requires Oracle support, this line of code will need to be modified to:

Petshopfactory factory = new Oraclefactory ();

This behavior of modifying the code is clearly unacceptable. The solution is "dependency injection". The function of "dependency injection" is usually provided by a dedicated IOC container, which, under the Java platform, includes Spring,picocontainer and so on. And in. Net platform, the most common is the spring.net. However, in a petshop system, there is no need for a dedicated container to implement "dependency injection", and the simple approach is to use configuration files and reflection functions. In other words, we can configure the complete class name of the specific factory object in the Web.config file. However, when we take advantage of the configuration files and reflection functions, the creation of a specific factory is a little "superfluous", we can in the configuration file directly to the specific database object implementation classes, such as PetShop.SQLServerDAL.IOrder. So, the related factories in the abstract factory model can be reduced to a factory class, so I call this pattern "the abstract factory model with simple factory characteristics", and its class diagram is as follows:

The DataAccess class completely replaces the factory class system created earlier, which is a sealed class where the methods for creating various data objects are static methods. The purpose of using this class to reach an abstract factory is because of the use of configuration files and reflections, as shown in the following code fragment:

public sealed class DataAccess
{
 //Look up the DAL implementation we should being using
 private static readonly String path = configurationmanager.appsettings["Webdal"];
 private static readonly string Orderpath = configurationmanager.appsettings["Ordersdal"];

 public static PetShop.IDAL.IOrder Createorder ()
 {
 string className = Orderpath + ". Order ";
 Return (PetShop.IDAL.IOrder) Assembly.Load (Orderpath). CreateInstance (ClassName);
 }


In PetShop, this relies on configuration files and reflection to create objects that are extremely common, including Ibllstategy, Cachedependencyfactory, and so on. These implementation logic is scattered throughout the PetShop system, which, in my opinion, can be reconstructed on this basis. In other words, we can provide an implementation similar to the Service Locator for the entire system:

 public static class Servicelocator {private static readonly string Dalpath = Configu
 rationmanager.appsettings["Webdal"];
 private static readonly string Orderpath = configurationmanager.appsettings["Ordersdal"];

 ... private static readonly string Orderstategypath = configurationmanager.appsettings["orderstrategyassembly"];
 public static Object Locatedalobject (String className) {string fullpath = Dalpath + "." + ClassName; Return Assembly.Load (Dalpath).
 CreateInstance (FullPath);
 public static Object Locatedalorderobject (String className) {string fullpath = Orderpath + '. ' + className; Return Assembly.Load (Orderpath).
 CreateInstance (FullPath); public static Object Locateorderstrategyobject (String className) {string fullpath = Orderstategypath + "." + Classna
 Me Return Assembly.Load (Orderstategypath).
 CreateInstance (FullPath);

} //...... } 

Then the code associated with the so-called "dependency injection" can be done using Servicelocator. For example, class DataAccess can be simplified to:

public sealed class DataAccess
{public
 static PetShop.IDAL.IOrder Createorder ()
 {return
 ( PetShop.IDAL.IOrder) Servicelocator. Locatedalorderobject ("Order");
 }

By Servicelocator, all the namespace values associated with the configuration files are managed uniformly, which facilitates the management and future maintenance of various dynamically created objects.

The above is PetShop data access design of the entire content, I hope to give you a reference, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.