DataSet and SqlDataAdapter objects are Microsoft in ADO. the new generation of data access methods introduced in. NET, in some cases, are very suitable for using DataSet, such as designing prototypes, developing small systems, and supporting utilities. However, using DataSet in enterprise systems may not be the best solution, because the ease of maintenance for enterprise systems is more important than the time invested in the market. So here we will discuss an alternative solution of DataSet, that is, custom entities and sets.
I. DataSet Problems
Question 1: Hard Coding
DataSet and databases not only share data, but unfortunately they also share the architecture.
For example :(
C # code for data access:
Public DataSet GetAllUsers ()
{
SqlConnection connection = new SqlConnection (CONNECTION_STRING );
SqlCommand command = new SqlCommand ("Select * from Users", connection );
Command. CommandType = CommandType. StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter (command );
DataSet ds = new DataSet ();
Da. Fill (ds );
Return ds;
}
Page code:
<Form id = "Form1" method = "post" runat = "server">
<Asp: Repeater ID = "users" Runat = "server">
<ItemTemplate>
<% # DataBinder. EvAl (Container. DataItem ,"FirstName") %>
<Br/>
</ItemTemplate>
</Asp: Repeater>
</Form>
In this example, we can see that the column name "FistName" is directly bound to the ASPX page ",If the structure of the database changes (such as changing the column name), this change will directly affect the interface layer of the database (although this code is not troublesome ).Is this still like the "N layer" structure? In a program, I think this isHard Coding. Using this type of development in large software may cause great trouble for future maintenance.
In addition,This encoding method also requires the user layer to know the database structureOf course, some people have suggested using strong DataSet and constants to solve this problem. But the encoding syntax here will make programmers very annoying. For example, ds. Tables [0]. Rows [I] ["userId"]. ToString () is not only difficult to read, but also requires familiarity with column names and their types. If DataSet is used like this,The business layer may be weak or complex.
Question 2: weak type problems
The values in the DataSet data table are returned in the form of System. Object. You need to convert these values.But the conversion may fail (for example, null value conversion, Type Mismatch conversion, and incorrect identifier). Unfortunately,A failure occurs not during compilation but during running.In addition, during conversion, we may encounter operations such as unpacking and packing.It consumes resources and reduces software performance.
Question 3: Object-oriented Constraints
DataSet is an object, but this object is still presented from the two-dimensional relationship in the database. One of our entity objects is converted into a record in the data table in DataSet, the relationship between objects becomes the Data Relationship between data tables ). The idea of object-oriented is to simulate objects in the program code to construct the attributes and methods of objects in the program, and then establish the reference and derivation relationships between program objects.
For this reason,It is difficult for our program code to reflect the relationships between objects and objects in our real life.
Therefore, DataSet can understand databases well, but cannot understand our lives well.
Ii. Custom object classes:(
A custom object class is a class abstracted from objects in real life. Its objects can reflect our life well. It makes good use of OO technologies such as inheritance and encapsulation.
For example:
Public class User
{
Private string userName;
Private string password;
Public string UserName
{
Get {return userName ;}
Set {userName = value ;}
}
Public string Password
{
Get {return password ;}
Set {password = value ;}
}
Public User (){}
Public User (string name, string password)
{
This. UserName = name;
This. Password = password;
}
}
A simple object class object can correspond to a record in the table, and its attribute can correspond to the field value of the record. The reference Association of other entity classes in the object class can correspond to the association relationship between the table and the table.
Next we will take a look at how to convert the structure and data in the database to our object.
Public User GetUser (string username)
{
SqlConnection conn = new SqlConnection ("server =.; database = mydb; uid = sa; pwd = sa ");
SqlCommand command = new SqlCommand ("select * from username where username = @ username", connection );
Command. Parameters. AddWithValue ("@ username", username );
SqlDataReader dr = null;
Conn. Open ();
Dr = command. ExecuteReader ();
If (dr. Read ())
{
User user = new User ();
User. UserName = Convert. ToString (dr ["UserName"]);
User. Password = Convert. ToString (dr ["Password"]);
Conn. Close ();
Return user;
}
Conn. Close ();
Return null;
}
Careful friends may have noticed the DataSet problem I mentioned earlier:
Weak type, low efficiency, and conversion errors due to database architecture changes, developers need to have a deep understanding of the basic data structure.
Take a look at the above Code and you may notice that these problems still exist. Note that,We have encapsulated these problems into a very isolated code area, rather than distributed across the entire program code as DataSet.
So far, we can convert a record in the database to an object class object. When we retrieve a batch of records from the database, how do we save it to the memory? The answer is of course a set of entity classes.
When it comes to collections, I think most people will think of ArrayList, but now the problem is that ArrayList itself is a weak collection, that is, any east and west can be placed in the ArrayList collection, data type conversion or unpacking are required. Isn't that the same as that of DataSet? In DotNet1.1, we had to use a custom set type (derived from the CollectionBase class) to implement a strongly typed set. However, due to the diversity of entity classes, it will inevitably bring about the diversity of entity classes, so that we spend a lot of time writing strong collections of various entity classes.
Fortunately, DotNet2.0 provides us with a new concept-- Generic. It frees people from writing a large number of strong entity classes. Here we will not talk much about the concept of generics. We will only focus on the most common generic set type -- List <T>
Iii. Generic set List <T>
List <T> The namespace of this generic set is: System. collections. generic is a strongly typed set. It also provides a series of set operation methods, such as adding, deleting, searching, and sorting.
The type "T" in the "T" is the "subrogation". When we instantiate the List <T>, it will be based on the value of "T, control our List <T> to store only the corresponding types of data.
For example:
List <User> list = new List <User> ();
This statement generates a set list,Each element in the set must be of the User data type.If you try to add other data types to our list set, a compilation exception will occur. In addition, when obtaining an element in the list set, you do not need to perform forced conversion because it stores the User type.
For example:
PublicList <User>GetUser (string username)
{
List <User> list = new List <User> ();
SqlConnection conn = new SqlConnection ("server =.; database = mydb; uid = sa; pwd = sa ");
SqlCommand command = new SqlCommand ("select * from username where username = @ username", connection );
Command. Parameters. AddWithValue ("@ username", username );
SqlDataReader dr = null;
Conn. Open ();
Dr = command. ExecuteReader ();
While (dr. Read ())
{
User user = new User ();
User. UserName = Convert. ToString (dr ["UserName"]);
User. Password = Convert. ToString (dr ["Password"]);
List. Add (user );
}
Conn. Close ();
Return list;
}
In VS2005, both our GridView and DataList can be bound to our entity class generic set, just as convenient as using DataSet binding .)
In a generic set, some methods Sort () can Sort the object classes, but if you simply use Sort () for sorting, an exception will occur. Because the object stored in List <User> is an object, the object is sorted by the object attribute. The List <User> object is unknown now. Unless our entity classImplement the IComparable <T> Interface.
The IComparable <T> interface has a method "int CompareTo (T)" that needs to be implemented., Write code in this method, compare the current object with the T object's related property values, and return the-, 0 values based on the comparison results, it serves as the basis for sorting objects in the List <T> object class.
For example:
Public class User: IComparable <User>
{
Private string _ UserName;
Private string _ Password;
Private
Public string UserName
{
Get {return _ UserName ;}
Set {_ UserName = value ;}
}
Public string Password
{
Get {return _ Password ;}
Set {_ Password = value ;}
}
Public User (){}
Public User (string name, string password)
{
This. UserName = name;
This. Password = password;
}
Public int CompareTo (User obj)
{
If (this. UserName> obj. UserName)
{
Return 1;
}
Else if (this. UserName <obj. UserName)
{
Return-1;
}
Else
{
Return 0;
}
}
}
Iv. Relationship between entity classes
For relational databases, you can maintain relationships through foreign keys. There is also a relationship between objects. In an object class, a link is a reference of an object class to another object. (
For example:
Public classRole: IComparable <Role>
{
Private string _ RoleId;
Private string _ RoleName;
Public string RoleId
{
Get {return _ RoleId ;}
Set {_ RoleId = value ;}
}
Public string RoleName
{
Get {return _ RoleName ;}
Set {_ RoleName = value ;}
}
Public Role (){}
Public Role (string roleid, string rolename)
{
This. _ RoleId = roleid;
This. _ RoleName = rolename;
}
Public int CompareTo (Role obj)
{
If (this. RoleId> obj. RoleId)
Return 1;
Else if (this. RoleId <obj. RoleId)
Return-1;
Else
Return 0;
}
}
Public classUser: IComparable <User>
{
Private string _ UserName;
Private string _ Password;
Private List <Role> _ Roles;
Public string UserName
{
Get {return _ UserName ;}
Set {_ UserName = value ;}
}
Public string Password
{
Get {return _ Password ;}
Set {_ Password = value ;}
}
Public List <Role> Roles
{
Get {return _ Role ;}
Set {_ Role = value ;}
}
Public User (){}
Public User (string name, string password)
{
This. UserName = name;
This. Password = password;
}
Public int CompareTo (User obj)
{
If (this. UserName> obj. UserName)
{
Return 1;
}
Else if (this. UserName <obj. UserName)
{
Return-1;
}
Else
{
Return 0;
}
}
}
Data Category:
// Role data category
Public class RoleDA
{
Private SqlConnection conn = new Conn (). Connection;
Public RoleDA ()
{
}
// Return the role object based on the role code
PublicRoleData select (string roleId)
{
RoleData rd = null;
SqlCommand cmd = conn. CreateCommand ();
Cmd. CommandText = "select * from [role] where roleid = @ roleid ";
Cmd. Parameters. AddWithValue ("@ roleid", roleId );
Conn. Open ();
SqlDataReader dr = cmd. ExecuteReader ();
While (dr. Read ())
{
Rd = new RoleData ();
Rd. RoleId = dr ["roleid"]. ToString ();
Rd. RoleName = dr ["rolename"]. ToString ();
}
Conn. Close ();
Return rd;
}
}
// User role relationship data category
Public class UserInRoleDA
{
Private SqlConnection conn = new Conn (). Connection;
Public UserInRoleDA ()
{
}
// Query the role list of the user based on the user name
PublicList <RoleData> select (string username)
{
List <RoleData> list = new List <RoleData> ();
RoleData rd = null;
SqlCommand cmd = conn. CreateCommand ();
Cmd. CommandText = "select * from userinrole where username = @ username ";
Cmd. Parameters. AddWithValue ("@ username", username );
Conn. Open ();
SqlDataReader dr = cmd. ExecuteReader ();
While (dr. Read ())
{
// Call the role data entity class to generate a role object
Rd = new RoleDA (). select (dr ["roleid"]. ToString ());
List. Add (rd );
}
Conn. Close ();
Return list;
}
}
// User data category
Public class UserDA
{
Private SqlConnection conn = new Conn (). Connection;
Public UserDA ()
{
}
// Returns the user entity pair based on the user name)
PublicUserData select (string username)
{
UserData user = null;
SqlCommand cmd = conn. CreateCommand ();
Cmd. CommandText = "select * from [user] where username = @ username ";
Cmd. Parameters. AddWithValue ("@ UserName", username );
Conn. Open ();
SqlDataReader dr = cmd. ExecuteReader ();
If (dr. Read ())
{
User = new UserData ();
User. UserName = dr ["username"]. ToString ();
User. Password = dr ["password"]. ToString ();
// Generate a list of roles owned by the user by calling the role class of user-role relationship data based on the user name
User. Roles = new UserInRoleDA (). select (user. UserName );
}
Conn. Close ();
Return user;
}
}
Client code:
UserData user = new UserDA (). select ("Fred L. Mannering ");
Response. Write ("UserName:" + user. UserName + "<br> ");
Response. Write ("Password:" + user. Password + "<br> ");
Foreach (RoleData role in user. Roles)
{
Response. Write ("> Role:" + role. RoleId. ToString () + "-" + role. RoleName + "<br> ");
}
Running result:
UserName: Fred L. Mannering
Password: aaa
> Role: R002-Manager
> Role: R003-Employee
The custom entity class provides you with a rich array of object-oriented programming functions and helps you build a reliable and maintainable N-layer architecture framework, it is also widely used in the industry.