标签:
https://msdn.microsoft.com/zh-cn/library/ms971499.aspx
http://www.c-sharpcorner.com/UploadFile/mosessaur/abstractfactoryadonet202152006053643AM/abstractfactoryadonet2.aspx
Most Web applications contain data access code to access the underlying data store to perform basic data operations such as Select, Update, Delete, and Insert. This article uses a step-by-step approach to show how page developers can take advantage of different ASP.NET 2.0 and ADO.NET 2.0 tools and techniques to write generic data access code that can be used to access different types of data stores. Writing generic data access code is especially important in data-driven Web applications because data comes from many different sources, including Microsoft SQL Server, Oracle, XML documents, flat files, and Web services, just to name a few.
This article uses a simple Web application as a test bed for all the code presented here. The application consists of two parts: the first part allows the system administrator to send newsletters to all subscribers of a mailing list. The second part allows users to subscribe or unsubscribe from a mailing list. The first part of the article begins by implementing a simple data access code (see Figure 1) to access Microsoft SQL Server and extract the list of subscribers. The code is modified and made more generic over the course of the article.
Figure 1. The GetSubscribers method extracts the list of all subscribers.
public IEnumerable GetSubscribers() { SqlConnection con = new SqlConnection(); con.ConnectionString = @"Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=D:\Application\Data\Database.mdf"; SqlCommand com = new SqlCommand(); com.Connection = con; com.CommandText = "Select * From Subscribers"; com.CommandType = CommandType.Text; DataSet ds = new DataSet(); SqlDataAdapter ad = new SqlDataAdapter(); ad.SelectCommand = com; con.Open(); ad.Fill(ds); con.Close(); return ds.Tables[0].DefaultView; }
Since the data access code in Figure 1 contains code for creating the ADO.NET objects, such as the SqlConnection, SqlCommand, and SqlDataAdapter instances. The data access code cannot be used to retrieve the list of subscribers from other data stores, such as an Oracle database. Page developers have to modify the data access code (using the GetSubscribers method) every time they need to access a new data store. Next, see how ADO.NET 2.0 uses the provider pattern to help page developers write generic data access code to access different types of data stores.
The main problem with the GetSubscribers method is that it contains the code for creating the ADO.NET objects. According to the provider pattern, the data access code must delegate the responsibility of providing the code for creating the ADO.NET objects to another class. I refer to this class as the "code provider class" because it provides the code for creating the ADO.NET objects. The code provider class exposes methods such as CreateConnection, CreateCommand, and CreateDataAdapter, where each method provides the code for creating the corresponding ADO.NET object.
Since the code provider class contains the actual code, the same class cannot be used to access different data stores. Therefore, the data access code (the GetSubscribers method) has to be modified and reconfigured to delegate the responsibility of providing the code to a new code provider class each time it is used to access a new data store. The GetSubscribers method is still tied to the code even though it does not contain the code.
The provider pattern offers a solution to this problem and consists of the following steps:
The abstract base class delegates the responsibility of providing the code for creating the ADO.NET objects to the appropriate subclass. The abstract base class is named DbProviderFactory. The following presents some of the methods of this class:
public abstract class DbProviderFactory { public virtual DbConnection CreateConnection(); public virtual DbCommand CreateCommand(); public virtual DbDataAdapter CreateDataAdapter(); }
Each subclass provides the code for creating the appropriate ADO.NET objects for a particular data store. For instance, the SqlClientFactory subclass provides the code for creating the ADO.NET objects to access Microsoft SQL Server, as shown in Figure 2.
Figure 2. The SqlClientFactory class and some of its methods
The provider pattern allows the data access code to treat all the subclasses the same because they are all subclasses of the same base class. As far as the data access code is concerned, all subclasses are of type DbProviderFactory. The data access code has no way of knowing the specific type of the subclass being used. This introduces a new problem. If the data access code (the GetSubscribers method) does not know the type of subclass, how can it then instantiate an instance of the subclass?
The provider pattern solution to this problem consists of the following three parts:
Data access code (the GetSubscribers method) calls the GetFactory static method and passes the appropriate unique string id to access the instance of the corresponding subclass. After the GetSubscribers method accesses the instance, it calls the appropriate creation methods, such as CreateConnection(), CreateCommand(), etc., to instantiate the appropriate ADO.NET objects, as shown in Figure 3.
Figure 3. The version of the GetSubscribers method that uses the new ADO.NET provider pattern
public IEnumerable GetSubscribers() { DbProviderFactory provider = DbProviderFactories.GetFactory("System.Data.SqlClient"); DbConnection con = provider.CreateConnection(); con.ConnectionString = @"Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=D:\Application\Data\Database.mdf"; DbCommand com = provider.CreateCommand(); com.Connection = con; com.CommandText = "Select * From Subscribers"; com.CommandType = CommandType.Text; DataSet ds = new DataSet(); DbDataAdapter ad = provider.CreateDataAdapter(); ad.SelectCommand = com; con.Open(); ad.Fill(ds); con.Close(); return ds.Tables[0].DefaultView; }
The data access code (the GetSubscribers method) delegates the responsibility of providing the code for creating the ADO.NET objects to the code provider class instance that the GetFactory method instantiates and returns. Therefore, the same data access code can be used to access different data stores, such as Microsoft SQL Server and Oracle.
The code for creating the right ADO.NET objects is data-store–specific. The provider pattern in ADO.NET 2.0 removes these data-store–specific parts from the data access code (the GetSubscribers method) to make it more generic. However, the provider pattern does not remove all the data-store–specific parts. Closer inspection of the GetSubscribers method reveals the following remaining data-store–specific parts:
Unless something is done about the above parts, the data access code is still tied to a particular type of data store. The provider pattern in ADO.NET 2.0 does not help with this problem. However, ADO.NET 2.0 provides us with other tools and techniques to remove the first two data-store–specific parts, such as the connection string and unique string id from the GetSubscribers method.
Connection strings are some of the most valuable resources in a Web application. They are so important that the .NET Framework 2.0 treats them as "first-class citizens". The web.config file now supports a new section named <connectionStrings> that contains all the connection strings used in an application. Therefore, we will move the connection string from the GetSubscribers method to this section:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="MySqlConnectionString" connectionString="Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=D:\Application\Data\Database.mdf" providerName="System.Data.SqlClient"/> </connectionStrings> </configuration>
The <add> subelement of the <connectionStrings> element exposes the following three important attributes:
NET Framework 2.0 provides the data access code (the GetSubscribers method) with the right tools to generically extract the connection string value from the web.config file as described in the following. TheSystem.Configuration namespace in .NET Framework 2.0 includes a new class named Configuration. This class represents the entire content of a web.config or machine.config file. The data access code cannot use the new operator to directly create an instance of this class.
Figure 4 shows the new version of the GetSubscribers method that contains the required code to extract the connection string in generic fashion.
Figure 4. The version of the GetSubscribers method that extracts the connection string from the web.config file
public IEnumerable GetSubscribers()
{
DbProviderFactory provider = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbConnection con = provider.CreateConnection();
Configuration configuration = Configuration.GetWebConfiguration("~/");
ConnectionStringsSection section = (ConnectionStringsSection)configuration.Sections["connectionStrings"];
con.ConnectionString = section.ConnectionStrings["MySqlConnectionString"].ConnectionString;
DbCommand com = provider.CreateCommand();
com.Connection = con;
com.CommandText = "Select * From Subscribers";
com.CommandType = CommandType.Text;
DataSet ds = new DataSet();
DbDataAdapter ad = provider.CreateDataAdapter();
ad.SelectCommand = com;
con.Open();
ad.Fill(ds);
con.Close();
return ds.Tables[0].DefaultView;
}
The GetSubscribers method now includes the MySqlConnectionString string, so we still have to modify the GetSubscribers method to add support for a different data store such as Oracle database. It would seem that we are back to square one. Not really. We have gained a few important benefits by moving the connection string from the data access code to the web.config file:
"Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=D:\Application\Data\Database.mdf"
with the new string, MySqlConnectionString. However, there is one big difference. The former string contains the SQL Server database-specific information that does not apply to another database such as Oracle, but the latter string is just a friendly name.
However, the friendly name could still cause problems because it refers to a specific connection string within the <connectionStrings> section of the web.config file. In our example, it refers to the connection string used to access Microsoft SQL Server. This means that the GetSubscribers method (the data access code) has to be modified to use a different friendly name to access a different data store such as Oracle.
To avoid modifying the data access code, we can move the friendly name from the data access code to the <appSettings> section of the web.config file and have the data access code dynamically extract it in runtime as follows:
string connectionStringName = ConfigurationSettings.AppSettings["ConnectionStringName"];
We also move the provider name to the <appSettings> section:
string providerName = ConfigurationSettings.AppSettings["ProviderName"];
Page developers simply change the value attribute of the <add> subelement of the <appSettings> element to the same data access code to access a different data store without making any changes in the data access code itself.
Figure 5 presents the version of the data access code (the GetSubscribers method) that contains the recent changes.
Figure 5. The version of the GetSubscribers method to extract the provider name and the friendly name of the connection string from the web.config file
public IEnumerable GetSubscribers() { string connectionStringName = ConfigurationSettings.AppSettings["ConnectionStringName"]; string providerName = ConfigurationSettings.AppSettings["ProviderName"]; Configuration configuration = Configuration.GetWebConfiguration("~/"); ConnectionStringsSection section = (ConnectionStringsSection)configuration.Sections["connectionStrings"]; DbProviderFactory provider = DbProviderFactories.GetFactory(providerName); DbConnection con = provider.CreateConnection(); con.ConnectionString = section.ConnectionStrings[connectionStringName].ConnectionString; DbCommand com = provider.CreateCommand(); com.Connection = con; com.CommandText = "Select * From Subscribers"; com.CommandType = CommandType.Text; DataSet ds = new DataSet(); DbDataAdapter ad = provider.CreateDataAdapter(); ad.SelectCommand = com; con.Open(); ad.Fill(ds); con.Close(); return ds.Tables[0].DefaultView; }
标签:
原文地址:http://www.cnblogs.com/chucklu/p/4495534.html