Introduction
Recently busy with the structure of the new project, has not updated the blog for some time, has been thinking about what to write, until one day with friends about their company development data layer encountered some problems, I think should share some of the data access patterns used in the project.
Although the use of the go language to develop the data server recently, but the language used in this article is still C #, the article provided in the code is only to share how to use the work unit, as to how to introduce this model into the project, you need to implement, after all, each project is not the same, It needs to be combined according to the specific environment of the project.
This article covers the following topics:
What is a work cell
based on the implementation summary of ADO
What is a unit of work
This pattern is used to maintain a list of business objects that have been modified by the business transaction (CRUD in addition to r) and to coordinate the persistence of these modifications and the concurrency of all tags.
In a Web application, because each user's request belongs to a different thread, it is necessary to keep all data operations for each request successfully committed, and as long as there is a failed operation, all actions of the user's request are rolled back to ensure that the data for the user's operation is always in a valid state.
More detailed information is required to view this article. based on the implementation of ADO
In the case of not using any data-tier framework, the general process is in the following way, using only ADO:
Instantiate IDbConnection
and then instantiate IDbCommand
settings idbcommand text and Parameters
execute idbcommand.executenoquery
Release IDbCommand, IDbConnection
In general, we will create a corresponding database interaction class for each database table and provide a crud method, other than R, the method will implement the above process.
However, if a user requests several cud operations at a time, it can only be cumbersome to use TransactionScope to wrap multiple operations before the user begins the data operation.
In fact, we can put the user's cud SQL statements and parameters are now saved, to the end of the commit, a bit like the look of the stored procedure, this is actually the work cell pattern, first to create a storage SQL statements and parameters of the class, the code is as follows:
Class Sqlentity
{
private string m_sql = null;
public string SQL
{
get {return m_sql;}
}
Private idataparameter[] m_parameters = null;
Public idataparameter[] Parameters
{
get {return m_parameters;}
}
Public Entity (String sql, params idataparameter[] parameters)
{
this.m_sql = SQL;
This.m_parameters = Parameters;
}
}
If you put all the cud operations in a list<sqlentity>, you only need to traverse the elements within the list<sqlentity> when you need to commit, and by repeating the START process (which requires a little refactoring), the code is as follows:
Class Sqlunitofwork {private IDbConnection m_connection = null;
Private list m_operations = new list ();
Public sqlunitofwork (IDbConnection connection) {this.m_connection = connection; } public void Registeradd (String sql, params idataparameter[] parameters) {this.m_operations.
ADD (New sqlentity (SQL, parameters)); } public void Registersave (String sql, params idataparameter[] parameters) {this.m_operations.
ADD (New sqlentity (SQL, parameters)); } public void Registerremove (String sql, params idataparameter[] parameters) {this.m_operations.
ADD (New sqlentity (SQL, parameters)); The public void Commit () {using (idbtransaction trans = this.m_connection. BeginTransaction ()) {try {using (IDbCommand cmd = this.m_connection). CreateCommand ()) {cmd.
Transaction = trans; Cmd.commandtype = CommandType.Text; This.
Executequeryby (CMD);
} trans.commit (); } catch (Exception ex) {trans.
Rollback ();
}}} private void Executequeryby (IDbCommand cmd) {foreach (var entity in this.m_operations) {Cmd.commandtext = entity.
SQL; Cmd.
Parameters.clear (); foreach (var parameter in entity. Parameters) {cmd.
Parameters.Add (parameter); } cmd.
ExecuteNonQuery (); } this.m_operations.
Clear (); }
}
With the above sqlunitofwork, our database class when calling the Cud method, just call the corresponding Registerxxx method, the data layer implementation code is as follows:
class schoolrepository {private sqlunitofwork m_uow = null;
Public schoolrepository (Sqlunitofwork uow) {this.m_uow = UOW; } public void Add (School School) {this.m_uow. Registeradd ("Insert school values (@id, @name)", New idbdataparameter[]{New SqlParameter ("@id", school. ID), New SqlParameter ("@name", school.
Name)}); } public void Save (School School) {this.m_uow. Registersave ("Update school set name = @name WHERE id = @id", New idbdataparameter[]{New SqlParameter ("@id", School. ID), New SqlParameter ("@name", school.
Name)}); } public void Remove (School School) {this.m_uow. Registerremove ("Delete from school where id = @id", New idbdataparameter[]{new SqlParameter ("id", school.
ID)}); }} class Studentrepository {//code is similar, so omit}
With the above preparation, use the following code to see the effect of the work cell, the code is as follows:
Sqlunitofwork UOW = new Sqlunitofwork (connection);
Schoolrepository schoolrepositry = new Schoolrepository (UOW);
Studentrepository studentrepository = new Studentrepository (UOW);
School School = new School
{
Id = Guid.NewGuid (). ToString (),
Name = "One Medium",
};
Schoolrepositry.add (school);
for (int i = 0; i < 7; i++)
{
Student Student = new Student
{
Id = Guid.NewGuid (). ToString (),
Name = string. Format ("Student {0} number", I), age
= 7 + I,
SchoolID = school. Id
};
Studentrepository.add (student);
}
School. Name = "two medium";
Schoolrepositry.save (school);
Uow.commit ();
You will then see the data in the graph in the database, as shown in the figure:
Summary
This completes the implementation of a simple work cell based on ADO, some people may have doubts, there are many different parts of the work unit implemented by others, because this version is only a general idea of implementation, and not with other frameworks, libraries, in order to make others understand the principle of work unit, Therefore, the implementation is relatively simple.
Because the pattern is a solution, a way of thinking, each project's environment, function, and structure are different, so the manner of implementation will vary. For patterns can not be memorized, to understand the principles, can be self-practice or reference to other people's code to achieve, if each project is copied mode, then lost its role.
In the next article, I will refactor the above code to implement a work unit that is compatible with the ADO/ORM Framework, then the article is here, if there are questions and questions welcome message, code for reference only do not apply to the actual project, thank you.