The Project's most basic thing is over, but now our project is not perfect. it is not conducive to testing repetitive code multilayer and layer coupling between layers is not conducive to expansion and so on. this chapter of today is mainly to solve these problems. Solve these problems, oneself also produced a lot of questions, understanding is not very thorough, I hope my question can be answered here ~ ~
I. Introduction to the Model
1.Repository
In Enterprise architecture mode, the domain is coordinated with the data mapping layer through an interface that is used to access a similar collection of domain Objects. Also please refer to this P of EAA detailed introduction
Then say my feelings and doubts about this how all feel this repository is the previous DAO (dal) layer ~ ~ But it is through the interface generic and ORM combination to achieve better reuse don't know
2.Unit of work
The Unit of work definition and interpretation are described First. The main solution is to change the data storage and transaction processing when there are multiple operations. The unit of work is a record of all the object model modified information, at the time of submission, the modification at once, and the results are synchronized to the Database. In fact, we can find that DbContext already has such a function ~ ~ to a large extent achieved unit of work~ because we savechange ()
Subset submitting the data
3. Overall overview
Use repository and unit of work to create an abstraction layer between the data layer and the business logic Layer. It will help us isolate the changes and be more conducive to testing.
Below are the differences between using repository and unit of work and not using the diagram illustrated below
Two. start of transformation
Let's go back to the first student controller and forget about what friends can look at this section-------student controller we put
Private Schoolcontext db = new Schoolcontext ();
It's written on each controller. the declaration period is fully coupled with the controller
1. Create student Repository interface
Using System;
Using System.Collections.Generic;
Using system.linq;
Using system.web;
Using contosouniversity.models;
Namespace Contosouniversity.dal
{
public interface Istudentrepository:idisposable
{
Ienumerable<student> getstudents ();
Student Getstudentbyid (int studentid);
void Insertstudent (Student Student);
void Deletestudent (int studentid);
void Updatestudent (Student Student);
void Save ();
}
}
2. Implementing the interface
Using System;
Using System.Collections.Generic;
Using system.linq;
Using system.data;
Using contosouniversity.models;
Namespace Contosouniversity.dal
{
public class studentrepository:istudentrepository, IDisposable
{
Private Schoolcontext context;
Public Studentrepository (schoolcontext Context)
{
This.context = context;
}
Public ienumerable<student> getstudents ()
{
Return to Context. Students.tolist ();
}
Public Student Getstudentbyid (int id)
{
Return to Context. Students.find (id);
}
public void Insertstudent (Student Student)
{
Context. Students.add (student);
}
public void Deletestudent (int Studentid)
{
Student Student = Context. Students.find (studentid);
Context. Students.remove (student);
}
public void Updatestudent (Student Student)
{
Context. Entry (student). State = entitystate.modified;
}
public void Save ()
{
Context. SaveChanges ();
}
private bool disposed = false;
protected virtual void Dispose (bool Disposing)
{
If (!this.disposed)
{
If (disposing)
{
Context. Dispose ();
}
}
this.disposed = true;
}
public void Dispose ()
{
Dispose (true);
Gc. SuppressFinalize (this);
}
}
}
3. Retrofit Student Controller
View Code
Through the above operation now our controller is for an interface and no longer directly through the dbcontext of course if we use the IOC container here will be able to achieve better decoupling we can look at
This article of quite Unruly's soul
4. Problems arising after the transformation
1. The dbcontext that we were supposed to implement in the controller is now in the repository because the project will have multiple repository so there will be multiple dbcontext! This is a time when we have
A complex logic to use multiple Repository, such as I casually say an example ~ ~ such as adding an order to update a detailed order and then delete a customer hypothesis this series of logic is together here will use three Repository we want to invoke a different Reposito SAVE in Ry () at this point we are going to do multiple commits and no longer a unified transaction. efficiency integrity is greatly reduced. Instead of losing
DbContext bring the benefits of unit of work ~ ~ It's okay, we're going to implement unit of work to retrofit the problem later.
2. The second problem is also a very serious one. we used to look for students in search sort and Pagination.
var students = from S in Context. Students
Select s;
If (! String.IsNullOrEmpty (searchstring))
{
Students = Students. Where (s = = S.lastname.toupper (). Contains (searchstring.toupper ())
|| S.firstmidname.toupper (). Contains (searchstring.toupper ()));
}
And now It's become
var students = from S in studentrepository.getstudents ()
Select s;
This is a serious problem IQueryable 而现在的是 .IEnumerable 变成了数据直接全部查找出来 所以再这里 我觉得Repository的查找 应该是返回IQueryable
Instead ofIEnumerable
要不然There was the first question I had in the Text. it's not just an ordinary crud, it's a normal data access Layer.
andRepository用法我觉得应该是 返回IQueryable 参数的接受应该是一个表达式树 不知道大家是否认同?希望大家帮我解决下疑惑 谢谢~
The following public generic Repository will embody this
THREE. Create a public repository
Look at the students above us, Repository. if we were to write the course, the code would be very similar, so we use generic injection to implement multiplexing. a generic interface and generic class should be implemented here
But the original is not implemented interface ~ only a class
Let me see this class.
Namespace Contosouniversity.dal
{
public class genericrepository<tentity> where Tentity:class
{
Internal Schoolcontext context;
Internal Dbset<tentity> DbSet;
Public Genericrepository (schoolcontext Context)
{
This.context = context;
This.dbset = Context. Set<tentity> ();
}
Public virtual ienumerable<tentity> Get (
expression<func<tentity, bool>> filter = null,
func<iqueryable<tentity>, iorderedqueryable<tentity>> = null,
String includeproperties = "")
{
iqueryable<tentity> query = dbSet;
If (filter! = Null)
{
query = Query. Where (filter);
}
foreach (var Includeproperty in Includeproperties.split
(new char[] {', '}, STRINGSPLITOPTIONS.REMOVEEMPTYENTRIES))
{
query = Query. Include (includeproperty);
}
if (~ = = Null)
{
Return (query). ToList ();
}
Else
{
Return query. ToList ();
}
}
Public virtual TEntity GetByID (object id)
{
return Dbset.find (id);
}
Public virtual void Insert (TEntity Entity)
{
Dbset.add (entity);
}
Public virtual void Delete (object Id)
{
TEntity Entitytodelete = Dbset.find (id);
Delete (entitytodelete);
}
Public virtual void Delete (TEntity Entitytodelete)
{
If (context. Entry (entitytodelete). state = = Entitystate.detached)
{
Dbset.attach (entitytodelete);
}
Dbset.remove (entitytodelete);
}
Public virtual void Update (TEntity Entitytoupdate)
{
Dbset.attach (entitytoupdate);
Context. Entry (entitytoupdate). State = entitystate.modified;
}
}
}
This is the way to focus Here.
public virtual ienumerable<tentity> Get (
expression<func<tentity, bool>> filter = Nu ll,
func<iqueryable<tentity>, iorderedqueryable<tentity>> = null,
String includeproperties = "")
{
iqueryable<tentity> query = dbSet;
If (filter! = Null)
{
query = query. Where (filter);
}
foreach (var includeproperty in Includeproperties.split
(new char[ ] {', '}, stringsplitoptions.removeemptyentries) '
{
query = query. Include (includeproperty);
}
If (out of! = Null)
{
return by (query). ToList ();
}
Else
{
return query. ToList ();
}
}
or, as I said above, I think it should be returned, IQueryable so I think we should get rid of the last One. ToList and return IQueryable
And then look at this method the first one to accept an expression tree is actually the filter condition the second is a delegate that is primarily used to sort the third accept to be greedy load which navigation properties can be separated by commas
And here take advantage of the next 4.0 of the function can give the parameter a default value is empty how to use this method will be written in the following ~ ~
There's One more place that I didn't mention Before.
Public virtual void Delete (TEntity Entitytodelete)
{
If (context. Entry (entitytodelete). state = = Entitystate.detached)
{
Dbset.attach (entitytodelete);
}
Dbset.remove (entitytodelete);
}
This Dbset.attach (entitytodelete); Represents the addition of an object to the database context managed by DbContext I have a little question here. is there any benefit of not adding this judgment?
Four. Create a Unit of work Class
The primary purpose of creating this class is to ensure that multiple repository can share a database context let's look at this class
Namespace Contosouniversity.dal
{
public class Unitofwork:idisposable
{
Private Schoolcontext context = new Schoolcontext ();
Private Genericrepository<department> departmentrepository;
Private Genericrepository<course> courserepository;
Public genericrepository<department> Departmentrepository
{
Get
{
if (this.departmentrepository = = Null)
{
This.departmentrepository = new Genericrepository<department> (context);
}
Return departmentrepository;
}
}
Public genericrepository<course> Courserepository
{
Get
{
if (this.courserepository = = Null)
{
This.courserepository = new Genericrepository<course> (context);
}
Return courserepository;
}
}
public void Save ()
{
Context. SaveChanges ();
}
private bool disposed = false;
protected virtual void Dispose (bool Disposing)
{
If (!this.disposed)
{
If (disposing)
{
Context. Dispose ();
}
}
this.disposed = true;
}
public void Dispose ()
{
Dispose (true);
Gc. SuppressFinalize (this);
}
}
}
Write the class that wants the unit of work to help you control the whole. here we only wrote Two.
Private Schoolcontext context = new Schoolcontext ();
Private Genericrepository<department> departmentrepository;
Private Genericrepository<course> courserepository;
Implement Read-only Properties
Public genericrepository<department> Departmentrepository
{
Get
{
if (this.departmentrepository = = Null)
{
This.departmentrepository = new Genericrepository<department> (context);
}
Return departmentrepository;
}
}
And finally the release of the Save and the resources
okay, now look at how to use This.
Five. Change the course controller
Original Controller Code
The original demo does not reflect the benefits of using unit of work because this example does not appear to have a logical use of multiple repositories of hope you understand this ~ ~ and so on after the article
I'm going to write a full demo to illustrate This. here, let's see what's going on Here.
Six. questions about the EF+MVC framework
1. Is it necessary to implement the Iunitofwork interface? The code probably does.
public interface Iunitofwork
{
void Save ();
Istudentrepository studentrepository {get;}
}
Implementing interfaces
public class Unitofwork:iunitofwork
{
Private SchoolEntities context = new SchoolEntities ();
Private Istudentrepository studentrepository;
Public Istudentrepository Studentrepository
{
Get
{
if (this.studentrepository = = Null)
{
This.studentrepository = new Studentrepository (context);
}
Return studentrepository;
}
}
public void Save ()
{
Context. SaveChanges ();
}
}
Controller
Private Iunitofwork unitofwork;
Public Studentcontroller (): this (new unitofwork ())
{
}
Public Studentcontroller (iunitofwork Unitofwork)
{
This.unitofwork = unitofwork;
}
2. Whether it is necessary to add a service layer services this layer between the controller and the dal, which is called by unitofwork, and so on is written on the servie, so the code in the controller will become very small, the personal feel should be added service layer, but What are the benefits of adding a IService interface to this interface? I've always felt that the interface is only for the data access Layer.
3. Here we are using the unit of work to complete the consistency of the transaction before I used
Using (TransactionScope transaction = new TransactionScope ()) {
....
Use this to achieve transactional consistency what do you think about this and unit of work? I have not studied this ~ but the small city years to this did a very good introduction thanks to the small city ~ we can refer to his this article
4. Our caches such as mongodb, which layer is it better to write to?
Six. Summary
After refactoring the code finally some of the items look like ~ ~ The following section tells about some of the other features of ef, such as executing SQL statements directly, and closing the trace State.
mvc3+ef4.1 Learning Series (eight)-----using repository and Unit of work refactoring project